diff options
Diffstat (limited to 'fs/ceph/super.c')
| -rw-r--r-- | fs/ceph/super.c | 1154 |
1 files changed, 472 insertions, 682 deletions
diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 9922628532b2..d6e0e0421891 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | 1 | ||
| 2 | #include "ceph_debug.h" | 2 | #include <linux/ceph/ceph_debug.h> |
| 3 | 3 | ||
| 4 | #include <linux/backing-dev.h> | 4 | #include <linux/backing-dev.h> |
| 5 | #include <linux/ctype.h> | 5 | #include <linux/ctype.h> |
| @@ -15,10 +15,13 @@ | |||
| 15 | #include <linux/statfs.h> | 15 | #include <linux/statfs.h> |
| 16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
| 17 | 17 | ||
| 18 | #include "decode.h" | ||
| 19 | #include "super.h" | 18 | #include "super.h" |
| 20 | #include "mon_client.h" | 19 | #include "mds_client.h" |
| 21 | #include "auth.h" | 20 | |
| 21 | #include <linux/ceph/decode.h> | ||
| 22 | #include <linux/ceph/mon_client.h> | ||
| 23 | #include <linux/ceph/auth.h> | ||
| 24 | #include <linux/ceph/debugfs.h> | ||
| 22 | 25 | ||
| 23 | /* | 26 | /* |
| 24 | * Ceph superblock operations | 27 | * Ceph superblock operations |
| @@ -26,36 +29,22 @@ | |||
| 26 | * Handle the basics of mounting, unmounting. | 29 | * Handle the basics of mounting, unmounting. |
| 27 | */ | 30 | */ |
| 28 | 31 | ||
| 29 | |||
| 30 | /* | ||
| 31 | * find filename portion of a path (/foo/bar/baz -> baz) | ||
| 32 | */ | ||
| 33 | const char *ceph_file_part(const char *s, int len) | ||
| 34 | { | ||
| 35 | const char *e = s + len; | ||
| 36 | |||
| 37 | while (e != s && *(e-1) != '/') | ||
| 38 | e--; | ||
| 39 | return e; | ||
| 40 | } | ||
| 41 | |||
| 42 | |||
| 43 | /* | 32 | /* |
| 44 | * super ops | 33 | * super ops |
| 45 | */ | 34 | */ |
| 46 | static void ceph_put_super(struct super_block *s) | 35 | static void ceph_put_super(struct super_block *s) |
| 47 | { | 36 | { |
| 48 | struct ceph_client *client = ceph_sb_to_client(s); | 37 | struct ceph_fs_client *fsc = ceph_sb_to_client(s); |
| 49 | 38 | ||
| 50 | dout("put_super\n"); | 39 | dout("put_super\n"); |
| 51 | ceph_mdsc_close_sessions(&client->mdsc); | 40 | ceph_mdsc_close_sessions(fsc->mdsc); |
| 52 | 41 | ||
| 53 | /* | 42 | /* |
| 54 | * ensure we release the bdi before put_anon_super releases | 43 | * ensure we release the bdi before put_anon_super releases |
| 55 | * the device name. | 44 | * the device name. |
| 56 | */ | 45 | */ |
| 57 | if (s->s_bdi == &client->backing_dev_info) { | 46 | if (s->s_bdi == &fsc->backing_dev_info) { |
| 58 | bdi_unregister(&client->backing_dev_info); | 47 | bdi_unregister(&fsc->backing_dev_info); |
| 59 | s->s_bdi = NULL; | 48 | s->s_bdi = NULL; |
| 60 | } | 49 | } |
| 61 | 50 | ||
| @@ -64,14 +53,14 @@ static void ceph_put_super(struct super_block *s) | |||
| 64 | 53 | ||
| 65 | static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf) | 54 | static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf) |
| 66 | { | 55 | { |
| 67 | struct ceph_client *client = ceph_inode_to_client(dentry->d_inode); | 56 | struct ceph_fs_client *fsc = ceph_inode_to_client(dentry->d_inode); |
| 68 | struct ceph_monmap *monmap = client->monc.monmap; | 57 | struct ceph_monmap *monmap = fsc->client->monc.monmap; |
| 69 | struct ceph_statfs st; | 58 | struct ceph_statfs st; |
| 70 | u64 fsid; | 59 | u64 fsid; |
| 71 | int err; | 60 | int err; |
| 72 | 61 | ||
| 73 | dout("statfs\n"); | 62 | dout("statfs\n"); |
| 74 | err = ceph_monc_do_statfs(&client->monc, &st); | 63 | err = ceph_monc_do_statfs(&fsc->client->monc, &st); |
| 75 | if (err < 0) | 64 | if (err < 0) |
| 76 | return err; | 65 | return err; |
| 77 | 66 | ||
| @@ -104,238 +93,28 @@ static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
| 104 | 93 | ||
| 105 | static int ceph_sync_fs(struct super_block *sb, int wait) | 94 | static int ceph_sync_fs(struct super_block *sb, int wait) |
| 106 | { | 95 | { |
| 107 | struct ceph_client *client = ceph_sb_to_client(sb); | 96 | struct ceph_fs_client *fsc = ceph_sb_to_client(sb); |
| 108 | 97 | ||
| 109 | if (!wait) { | 98 | if (!wait) { |
| 110 | dout("sync_fs (non-blocking)\n"); | 99 | dout("sync_fs (non-blocking)\n"); |
| 111 | ceph_flush_dirty_caps(&client->mdsc); | 100 | ceph_flush_dirty_caps(fsc->mdsc); |
| 112 | dout("sync_fs (non-blocking) done\n"); | 101 | dout("sync_fs (non-blocking) done\n"); |
| 113 | return 0; | 102 | return 0; |
| 114 | } | 103 | } |
| 115 | 104 | ||
| 116 | dout("sync_fs (blocking)\n"); | 105 | dout("sync_fs (blocking)\n"); |
| 117 | ceph_osdc_sync(&ceph_sb_to_client(sb)->osdc); | 106 | ceph_osdc_sync(&fsc->client->osdc); |
| 118 | ceph_mdsc_sync(&ceph_sb_to_client(sb)->mdsc); | 107 | ceph_mdsc_sync(fsc->mdsc); |
| 119 | dout("sync_fs (blocking) done\n"); | 108 | dout("sync_fs (blocking) done\n"); |
| 120 | return 0; | 109 | return 0; |
| 121 | } | 110 | } |
| 122 | 111 | ||
| 123 | static int default_congestion_kb(void) | ||
| 124 | { | ||
| 125 | int congestion_kb; | ||
| 126 | |||
| 127 | /* | ||
| 128 | * Copied from NFS | ||
| 129 | * | ||
| 130 | * congestion size, scale with available memory. | ||
| 131 | * | ||
| 132 | * 64MB: 8192k | ||
| 133 | * 128MB: 11585k | ||
| 134 | * 256MB: 16384k | ||
| 135 | * 512MB: 23170k | ||
| 136 | * 1GB: 32768k | ||
| 137 | * 2GB: 46340k | ||
| 138 | * 4GB: 65536k | ||
| 139 | * 8GB: 92681k | ||
| 140 | * 16GB: 131072k | ||
| 141 | * | ||
| 142 | * This allows larger machines to have larger/more transfers. | ||
| 143 | * Limit the default to 256M | ||
| 144 | */ | ||
| 145 | congestion_kb = (16*int_sqrt(totalram_pages)) << (PAGE_SHIFT-10); | ||
| 146 | if (congestion_kb > 256*1024) | ||
| 147 | congestion_kb = 256*1024; | ||
| 148 | |||
| 149 | return congestion_kb; | ||
| 150 | } | ||
| 151 | |||
| 152 | /** | ||
| 153 | * ceph_show_options - Show mount options in /proc/mounts | ||
| 154 | * @m: seq_file to write to | ||
| 155 | * @mnt: mount descriptor | ||
| 156 | */ | ||
| 157 | static int ceph_show_options(struct seq_file *m, struct vfsmount *mnt) | ||
| 158 | { | ||
| 159 | struct ceph_client *client = ceph_sb_to_client(mnt->mnt_sb); | ||
| 160 | struct ceph_mount_args *args = client->mount_args; | ||
| 161 | |||
| 162 | if (args->flags & CEPH_OPT_FSID) | ||
| 163 | seq_printf(m, ",fsid=%pU", &args->fsid); | ||
| 164 | if (args->flags & CEPH_OPT_NOSHARE) | ||
| 165 | seq_puts(m, ",noshare"); | ||
| 166 | if (args->flags & CEPH_OPT_DIRSTAT) | ||
| 167 | seq_puts(m, ",dirstat"); | ||
| 168 | if ((args->flags & CEPH_OPT_RBYTES) == 0) | ||
| 169 | seq_puts(m, ",norbytes"); | ||
| 170 | if (args->flags & CEPH_OPT_NOCRC) | ||
| 171 | seq_puts(m, ",nocrc"); | ||
| 172 | if (args->flags & CEPH_OPT_NOASYNCREADDIR) | ||
| 173 | seq_puts(m, ",noasyncreaddir"); | ||
| 174 | |||
| 175 | if (args->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT) | ||
| 176 | seq_printf(m, ",mount_timeout=%d", args->mount_timeout); | ||
| 177 | if (args->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT) | ||
| 178 | seq_printf(m, ",osd_idle_ttl=%d", args->osd_idle_ttl); | ||
| 179 | if (args->osd_timeout != CEPH_OSD_TIMEOUT_DEFAULT) | ||
| 180 | seq_printf(m, ",osdtimeout=%d", args->osd_timeout); | ||
| 181 | if (args->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT) | ||
| 182 | seq_printf(m, ",osdkeepalivetimeout=%d", | ||
| 183 | args->osd_keepalive_timeout); | ||
| 184 | if (args->wsize) | ||
| 185 | seq_printf(m, ",wsize=%d", args->wsize); | ||
| 186 | if (args->rsize != CEPH_MOUNT_RSIZE_DEFAULT) | ||
| 187 | seq_printf(m, ",rsize=%d", args->rsize); | ||
| 188 | if (args->congestion_kb != default_congestion_kb()) | ||
| 189 | seq_printf(m, ",write_congestion_kb=%d", args->congestion_kb); | ||
| 190 | if (args->caps_wanted_delay_min != CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT) | ||
| 191 | seq_printf(m, ",caps_wanted_delay_min=%d", | ||
| 192 | args->caps_wanted_delay_min); | ||
| 193 | if (args->caps_wanted_delay_max != CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT) | ||
| 194 | seq_printf(m, ",caps_wanted_delay_max=%d", | ||
| 195 | args->caps_wanted_delay_max); | ||
| 196 | if (args->cap_release_safety != CEPH_CAP_RELEASE_SAFETY_DEFAULT) | ||
| 197 | seq_printf(m, ",cap_release_safety=%d", | ||
| 198 | args->cap_release_safety); | ||
| 199 | if (args->max_readdir != CEPH_MAX_READDIR_DEFAULT) | ||
| 200 | seq_printf(m, ",readdir_max_entries=%d", args->max_readdir); | ||
| 201 | if (args->max_readdir_bytes != CEPH_MAX_READDIR_BYTES_DEFAULT) | ||
| 202 | seq_printf(m, ",readdir_max_bytes=%d", args->max_readdir_bytes); | ||
| 203 | if (strcmp(args->snapdir_name, CEPH_SNAPDIRNAME_DEFAULT)) | ||
| 204 | seq_printf(m, ",snapdirname=%s", args->snapdir_name); | ||
| 205 | if (args->name) | ||
| 206 | seq_printf(m, ",name=%s", args->name); | ||
| 207 | if (args->secret) | ||
| 208 | seq_puts(m, ",secret=<hidden>"); | ||
| 209 | return 0; | ||
| 210 | } | ||
| 211 | |||
| 212 | /* | ||
| 213 | * caches | ||
| 214 | */ | ||
| 215 | struct kmem_cache *ceph_inode_cachep; | ||
| 216 | struct kmem_cache *ceph_cap_cachep; | ||
| 217 | struct kmem_cache *ceph_dentry_cachep; | ||
| 218 | struct kmem_cache *ceph_file_cachep; | ||
| 219 | |||
| 220 | static void ceph_inode_init_once(void *foo) | ||
| 221 | { | ||
| 222 | struct ceph_inode_info *ci = foo; | ||
| 223 | inode_init_once(&ci->vfs_inode); | ||
| 224 | } | ||
| 225 | |||
| 226 | static int __init init_caches(void) | ||
| 227 | { | ||
| 228 | ceph_inode_cachep = kmem_cache_create("ceph_inode_info", | ||
| 229 | sizeof(struct ceph_inode_info), | ||
| 230 | __alignof__(struct ceph_inode_info), | ||
| 231 | (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD), | ||
| 232 | ceph_inode_init_once); | ||
| 233 | if (ceph_inode_cachep == NULL) | ||
| 234 | return -ENOMEM; | ||
| 235 | |||
| 236 | ceph_cap_cachep = KMEM_CACHE(ceph_cap, | ||
| 237 | SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD); | ||
| 238 | if (ceph_cap_cachep == NULL) | ||
| 239 | goto bad_cap; | ||
| 240 | |||
| 241 | ceph_dentry_cachep = KMEM_CACHE(ceph_dentry_info, | ||
| 242 | SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD); | ||
| 243 | if (ceph_dentry_cachep == NULL) | ||
| 244 | goto bad_dentry; | ||
| 245 | |||
| 246 | ceph_file_cachep = KMEM_CACHE(ceph_file_info, | ||
| 247 | SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD); | ||
| 248 | if (ceph_file_cachep == NULL) | ||
| 249 | goto bad_file; | ||
| 250 | |||
| 251 | return 0; | ||
| 252 | |||
| 253 | bad_file: | ||
| 254 | kmem_cache_destroy(ceph_dentry_cachep); | ||
| 255 | bad_dentry: | ||
| 256 | kmem_cache_destroy(ceph_cap_cachep); | ||
| 257 | bad_cap: | ||
| 258 | kmem_cache_destroy(ceph_inode_cachep); | ||
| 259 | return -ENOMEM; | ||
| 260 | } | ||
| 261 | |||
| 262 | static void destroy_caches(void) | ||
| 263 | { | ||
| 264 | kmem_cache_destroy(ceph_inode_cachep); | ||
| 265 | kmem_cache_destroy(ceph_cap_cachep); | ||
| 266 | kmem_cache_destroy(ceph_dentry_cachep); | ||
| 267 | kmem_cache_destroy(ceph_file_cachep); | ||
| 268 | } | ||
| 269 | |||
| 270 | |||
| 271 | /* | ||
| 272 | * ceph_umount_begin - initiate forced umount. Tear down down the | ||
| 273 | * mount, skipping steps that may hang while waiting for server(s). | ||
| 274 | */ | ||
| 275 | static void ceph_umount_begin(struct super_block *sb) | ||
| 276 | { | ||
| 277 | struct ceph_client *client = ceph_sb_to_client(sb); | ||
| 278 | |||
| 279 | dout("ceph_umount_begin - starting forced umount\n"); | ||
| 280 | if (!client) | ||
| 281 | return; | ||
| 282 | client->mount_state = CEPH_MOUNT_SHUTDOWN; | ||
| 283 | return; | ||
| 284 | } | ||
| 285 | |||
| 286 | static const struct super_operations ceph_super_ops = { | ||
| 287 | .alloc_inode = ceph_alloc_inode, | ||
| 288 | .destroy_inode = ceph_destroy_inode, | ||
| 289 | .write_inode = ceph_write_inode, | ||
| 290 | .sync_fs = ceph_sync_fs, | ||
| 291 | .put_super = ceph_put_super, | ||
| 292 | .show_options = ceph_show_options, | ||
| 293 | .statfs = ceph_statfs, | ||
| 294 | .umount_begin = ceph_umount_begin, | ||
| 295 | }; | ||
| 296 | |||
| 297 | |||
| 298 | const char *ceph_msg_type_name(int type) | ||
| 299 | { | ||
| 300 | switch (type) { | ||
| 301 | case CEPH_MSG_SHUTDOWN: return "shutdown"; | ||
| 302 | case CEPH_MSG_PING: return "ping"; | ||
| 303 | case CEPH_MSG_AUTH: return "auth"; | ||
| 304 | case CEPH_MSG_AUTH_REPLY: return "auth_reply"; | ||
| 305 | case CEPH_MSG_MON_MAP: return "mon_map"; | ||
| 306 | case CEPH_MSG_MON_GET_MAP: return "mon_get_map"; | ||
| 307 | case CEPH_MSG_MON_SUBSCRIBE: return "mon_subscribe"; | ||
| 308 | case CEPH_MSG_MON_SUBSCRIBE_ACK: return "mon_subscribe_ack"; | ||
| 309 | case CEPH_MSG_STATFS: return "statfs"; | ||
| 310 | case CEPH_MSG_STATFS_REPLY: return "statfs_reply"; | ||
| 311 | case CEPH_MSG_MDS_MAP: return "mds_map"; | ||
| 312 | case CEPH_MSG_CLIENT_SESSION: return "client_session"; | ||
| 313 | case CEPH_MSG_CLIENT_RECONNECT: return "client_reconnect"; | ||
| 314 | case CEPH_MSG_CLIENT_REQUEST: return "client_request"; | ||
| 315 | case CEPH_MSG_CLIENT_REQUEST_FORWARD: return "client_request_forward"; | ||
| 316 | case CEPH_MSG_CLIENT_REPLY: return "client_reply"; | ||
| 317 | case CEPH_MSG_CLIENT_CAPS: return "client_caps"; | ||
| 318 | case CEPH_MSG_CLIENT_CAPRELEASE: return "client_cap_release"; | ||
| 319 | case CEPH_MSG_CLIENT_SNAP: return "client_snap"; | ||
| 320 | case CEPH_MSG_CLIENT_LEASE: return "client_lease"; | ||
| 321 | case CEPH_MSG_OSD_MAP: return "osd_map"; | ||
| 322 | case CEPH_MSG_OSD_OP: return "osd_op"; | ||
| 323 | case CEPH_MSG_OSD_OPREPLY: return "osd_opreply"; | ||
| 324 | default: return "unknown"; | ||
| 325 | } | ||
| 326 | } | ||
| 327 | |||
| 328 | |||
| 329 | /* | 112 | /* |
| 330 | * mount options | 113 | * mount options |
| 331 | */ | 114 | */ |
| 332 | enum { | 115 | enum { |
| 333 | Opt_wsize, | 116 | Opt_wsize, |
| 334 | Opt_rsize, | 117 | Opt_rsize, |
| 335 | Opt_osdtimeout, | ||
| 336 | Opt_osdkeepalivetimeout, | ||
| 337 | Opt_mount_timeout, | ||
| 338 | Opt_osd_idle_ttl, | ||
| 339 | Opt_caps_wanted_delay_min, | 118 | Opt_caps_wanted_delay_min, |
| 340 | Opt_caps_wanted_delay_max, | 119 | Opt_caps_wanted_delay_max, |
| 341 | Opt_cap_release_safety, | 120 | Opt_cap_release_safety, |
| @@ -344,29 +123,19 @@ enum { | |||
| 344 | Opt_congestion_kb, | 123 | Opt_congestion_kb, |
| 345 | Opt_last_int, | 124 | Opt_last_int, |
| 346 | /* int args above */ | 125 | /* int args above */ |
| 347 | Opt_fsid, | ||
| 348 | Opt_snapdirname, | 126 | Opt_snapdirname, |
| 349 | Opt_name, | ||
| 350 | Opt_secret, | ||
| 351 | Opt_last_string, | 127 | Opt_last_string, |
| 352 | /* string args above */ | 128 | /* string args above */ |
| 353 | Opt_ip, | ||
| 354 | Opt_noshare, | ||
| 355 | Opt_dirstat, | 129 | Opt_dirstat, |
| 356 | Opt_nodirstat, | 130 | Opt_nodirstat, |
| 357 | Opt_rbytes, | 131 | Opt_rbytes, |
| 358 | Opt_norbytes, | 132 | Opt_norbytes, |
| 359 | Opt_nocrc, | ||
| 360 | Opt_noasyncreaddir, | 133 | Opt_noasyncreaddir, |
| 361 | }; | 134 | }; |
| 362 | 135 | ||
| 363 | static match_table_t arg_tokens = { | 136 | static match_table_t fsopt_tokens = { |
| 364 | {Opt_wsize, "wsize=%d"}, | 137 | {Opt_wsize, "wsize=%d"}, |
| 365 | {Opt_rsize, "rsize=%d"}, | 138 | {Opt_rsize, "rsize=%d"}, |
| 366 | {Opt_osdtimeout, "osdtimeout=%d"}, | ||
| 367 | {Opt_osdkeepalivetimeout, "osdkeepalive=%d"}, | ||
| 368 | {Opt_mount_timeout, "mount_timeout=%d"}, | ||
| 369 | {Opt_osd_idle_ttl, "osd_idle_ttl=%d"}, | ||
| 370 | {Opt_caps_wanted_delay_min, "caps_wanted_delay_min=%d"}, | 139 | {Opt_caps_wanted_delay_min, "caps_wanted_delay_min=%d"}, |
| 371 | {Opt_caps_wanted_delay_max, "caps_wanted_delay_max=%d"}, | 140 | {Opt_caps_wanted_delay_max, "caps_wanted_delay_max=%d"}, |
| 372 | {Opt_cap_release_safety, "cap_release_safety=%d"}, | 141 | {Opt_cap_release_safety, "cap_release_safety=%d"}, |
| @@ -374,403 +143,459 @@ static match_table_t arg_tokens = { | |||
| 374 | {Opt_readdir_max_bytes, "readdir_max_bytes=%d"}, | 143 | {Opt_readdir_max_bytes, "readdir_max_bytes=%d"}, |
| 375 | {Opt_congestion_kb, "write_congestion_kb=%d"}, | 144 | {Opt_congestion_kb, "write_congestion_kb=%d"}, |
| 376 | /* int args above */ | 145 | /* int args above */ |
| 377 | {Opt_fsid, "fsid=%s"}, | ||
| 378 | {Opt_snapdirname, "snapdirname=%s"}, | 146 | {Opt_snapdirname, "snapdirname=%s"}, |
| 379 | {Opt_name, "name=%s"}, | ||
| 380 | {Opt_secret, "secret=%s"}, | ||
| 381 | /* string args above */ | 147 | /* string args above */ |
| 382 | {Opt_ip, "ip=%s"}, | ||
| 383 | {Opt_noshare, "noshare"}, | ||
| 384 | {Opt_dirstat, "dirstat"}, | 148 | {Opt_dirstat, "dirstat"}, |
| 385 | {Opt_nodirstat, "nodirstat"}, | 149 | {Opt_nodirstat, "nodirstat"}, |
| 386 | {Opt_rbytes, "rbytes"}, | 150 | {Opt_rbytes, "rbytes"}, |
| 387 | {Opt_norbytes, "norbytes"}, | 151 | {Opt_norbytes, "norbytes"}, |
| 388 | {Opt_nocrc, "nocrc"}, | ||
| 389 | {Opt_noasyncreaddir, "noasyncreaddir"}, | 152 | {Opt_noasyncreaddir, "noasyncreaddir"}, |
| 390 | {-1, NULL} | 153 | {-1, NULL} |
| 391 | }; | 154 | }; |
| 392 | 155 | ||
| 393 | static int parse_fsid(const char *str, struct ceph_fsid *fsid) | 156 | static int parse_fsopt_token(char *c, void *private) |
| 394 | { | 157 | { |
| 395 | int i = 0; | 158 | struct ceph_mount_options *fsopt = private; |
| 396 | char tmp[3]; | 159 | substring_t argstr[MAX_OPT_ARGS]; |
| 397 | int err = -EINVAL; | 160 | int token, intval, ret; |
| 398 | int d; | 161 | |
| 399 | 162 | token = match_token((char *)c, fsopt_tokens, argstr); | |
| 400 | dout("parse_fsid '%s'\n", str); | 163 | if (token < 0) |
| 401 | tmp[2] = 0; | 164 | return -EINVAL; |
| 402 | while (*str && i < 16) { | 165 | |
| 403 | if (ispunct(*str)) { | 166 | if (token < Opt_last_int) { |
| 404 | str++; | 167 | ret = match_int(&argstr[0], &intval); |
| 405 | continue; | 168 | if (ret < 0) { |
| 169 | pr_err("bad mount option arg (not int) " | ||
| 170 | "at '%s'\n", c); | ||
| 171 | return ret; | ||
| 406 | } | 172 | } |
| 407 | if (!isxdigit(str[0]) || !isxdigit(str[1])) | 173 | dout("got int token %d val %d\n", token, intval); |
| 408 | break; | 174 | } else if (token > Opt_last_int && token < Opt_last_string) { |
| 409 | tmp[0] = str[0]; | 175 | dout("got string token %d val %s\n", token, |
| 410 | tmp[1] = str[1]; | 176 | argstr[0].from); |
| 411 | if (sscanf(tmp, "%x", &d) < 1) | 177 | } else { |
| 412 | break; | 178 | dout("got token %d\n", token); |
| 413 | fsid->fsid[i] = d & 0xff; | ||
| 414 | i++; | ||
| 415 | str += 2; | ||
| 416 | } | 179 | } |
| 417 | 180 | ||
| 418 | if (i == 16) | 181 | switch (token) { |
| 419 | err = 0; | 182 | case Opt_snapdirname: |
| 420 | dout("parse_fsid ret %d got fsid %pU", err, fsid); | 183 | kfree(fsopt->snapdir_name); |
| 421 | return err; | 184 | fsopt->snapdir_name = kstrndup(argstr[0].from, |
| 185 | argstr[0].to-argstr[0].from, | ||
| 186 | GFP_KERNEL); | ||
| 187 | if (!fsopt->snapdir_name) | ||
| 188 | return -ENOMEM; | ||
| 189 | break; | ||
| 190 | |||
| 191 | /* misc */ | ||
| 192 | case Opt_wsize: | ||
| 193 | fsopt->wsize = intval; | ||
| 194 | break; | ||
| 195 | case Opt_rsize: | ||
| 196 | fsopt->rsize = intval; | ||
| 197 | break; | ||
| 198 | case Opt_caps_wanted_delay_min: | ||
| 199 | fsopt->caps_wanted_delay_min = intval; | ||
| 200 | break; | ||
| 201 | case Opt_caps_wanted_delay_max: | ||
| 202 | fsopt->caps_wanted_delay_max = intval; | ||
| 203 | break; | ||
| 204 | case Opt_readdir_max_entries: | ||
| 205 | fsopt->max_readdir = intval; | ||
| 206 | break; | ||
| 207 | case Opt_readdir_max_bytes: | ||
| 208 | fsopt->max_readdir_bytes = intval; | ||
| 209 | break; | ||
| 210 | case Opt_congestion_kb: | ||
| 211 | fsopt->congestion_kb = intval; | ||
| 212 | break; | ||
| 213 | case Opt_dirstat: | ||
| 214 | fsopt->flags |= CEPH_MOUNT_OPT_DIRSTAT; | ||
| 215 | break; | ||
| 216 | case Opt_nodirstat: | ||
| 217 | fsopt->flags &= ~CEPH_MOUNT_OPT_DIRSTAT; | ||
| 218 | break; | ||
| 219 | case Opt_rbytes: | ||
| 220 | fsopt->flags |= CEPH_MOUNT_OPT_RBYTES; | ||
| 221 | break; | ||
| 222 | case Opt_norbytes: | ||
| 223 | fsopt->flags &= ~CEPH_MOUNT_OPT_RBYTES; | ||
| 224 | break; | ||
| 225 | case Opt_noasyncreaddir: | ||
| 226 | fsopt->flags |= CEPH_MOUNT_OPT_NOASYNCREADDIR; | ||
| 227 | break; | ||
| 228 | default: | ||
| 229 | BUG_ON(token); | ||
| 230 | } | ||
| 231 | return 0; | ||
| 422 | } | 232 | } |
| 423 | 233 | ||
| 424 | static struct ceph_mount_args *parse_mount_args(int flags, char *options, | 234 | static void destroy_mount_options(struct ceph_mount_options *args) |
| 425 | const char *dev_name, | ||
| 426 | const char **path) | ||
| 427 | { | 235 | { |
| 428 | struct ceph_mount_args *args; | 236 | dout("destroy_mount_options %p\n", args); |
| 429 | const char *c; | 237 | kfree(args->snapdir_name); |
| 430 | int err = -ENOMEM; | 238 | kfree(args); |
| 431 | substring_t argstr[MAX_OPT_ARGS]; | 239 | } |
| 432 | 240 | ||
| 433 | args = kzalloc(sizeof(*args), GFP_KERNEL); | 241 | static int strcmp_null(const char *s1, const char *s2) |
| 434 | if (!args) | 242 | { |
| 435 | return ERR_PTR(-ENOMEM); | 243 | if (!s1 && !s2) |
| 436 | args->mon_addr = kcalloc(CEPH_MAX_MON, sizeof(*args->mon_addr), | 244 | return 0; |
| 437 | GFP_KERNEL); | 245 | if (s1 && !s2) |
| 438 | if (!args->mon_addr) | 246 | return -1; |
| 439 | goto out; | 247 | if (!s1 && s2) |
| 248 | return 1; | ||
| 249 | return strcmp(s1, s2); | ||
| 250 | } | ||
| 440 | 251 | ||
| 441 | dout("parse_mount_args %p, dev_name '%s'\n", args, dev_name); | 252 | static int compare_mount_options(struct ceph_mount_options *new_fsopt, |
| 442 | 253 | struct ceph_options *new_opt, | |
| 443 | /* start with defaults */ | 254 | struct ceph_fs_client *fsc) |
| 444 | args->sb_flags = flags; | 255 | { |
| 445 | args->flags = CEPH_OPT_DEFAULT; | 256 | struct ceph_mount_options *fsopt1 = new_fsopt; |
| 446 | args->osd_timeout = CEPH_OSD_TIMEOUT_DEFAULT; | 257 | struct ceph_mount_options *fsopt2 = fsc->mount_options; |
| 447 | args->osd_keepalive_timeout = CEPH_OSD_KEEPALIVE_DEFAULT; | 258 | int ofs = offsetof(struct ceph_mount_options, snapdir_name); |
| 448 | args->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT; /* seconds */ | 259 | int ret; |
| 449 | args->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT; /* seconds */ | ||
| 450 | args->caps_wanted_delay_min = CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT; | ||
| 451 | args->caps_wanted_delay_max = CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT; | ||
| 452 | args->rsize = CEPH_MOUNT_RSIZE_DEFAULT; | ||
| 453 | args->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL); | ||
| 454 | args->cap_release_safety = CEPH_CAP_RELEASE_SAFETY_DEFAULT; | ||
| 455 | args->max_readdir = CEPH_MAX_READDIR_DEFAULT; | ||
| 456 | args->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT; | ||
| 457 | args->congestion_kb = default_congestion_kb(); | ||
| 458 | |||
| 459 | /* ip1[:port1][,ip2[:port2]...]:/subdir/in/fs */ | ||
| 460 | err = -EINVAL; | ||
| 461 | if (!dev_name) | ||
| 462 | goto out; | ||
| 463 | *path = strstr(dev_name, ":/"); | ||
| 464 | if (*path == NULL) { | ||
| 465 | pr_err("device name is missing path (no :/ in %s)\n", | ||
| 466 | dev_name); | ||
| 467 | goto out; | ||
| 468 | } | ||
| 469 | 260 | ||
| 470 | /* get mon ip(s) */ | 261 | ret = memcmp(fsopt1, fsopt2, ofs); |
| 471 | err = ceph_parse_ips(dev_name, *path, args->mon_addr, | 262 | if (ret) |
| 472 | CEPH_MAX_MON, &args->num_mon); | 263 | return ret; |
| 473 | if (err < 0) | 264 | |
| 474 | goto out; | 265 | ret = strcmp_null(fsopt1->snapdir_name, fsopt2->snapdir_name); |
| 266 | if (ret) | ||
| 267 | return ret; | ||
| 268 | |||
| 269 | return ceph_compare_options(new_opt, fsc->client); | ||
| 270 | } | ||
| 271 | |||
| 272 | static int parse_mount_options(struct ceph_mount_options **pfsopt, | ||
| 273 | struct ceph_options **popt, | ||
| 274 | int flags, char *options, | ||
| 275 | const char *dev_name, | ||
| 276 | const char **path) | ||
| 277 | { | ||
| 278 | struct ceph_mount_options *fsopt; | ||
| 279 | const char *dev_name_end; | ||
| 280 | int err = -ENOMEM; | ||
| 281 | |||
| 282 | fsopt = kzalloc(sizeof(*fsopt), GFP_KERNEL); | ||
| 283 | if (!fsopt) | ||
| 284 | return -ENOMEM; | ||
| 285 | |||
| 286 | dout("parse_mount_options %p, dev_name '%s'\n", fsopt, dev_name); | ||
| 287 | |||
| 288 | fsopt->sb_flags = flags; | ||
| 289 | fsopt->flags = CEPH_MOUNT_OPT_DEFAULT; | ||
| 290 | |||
| 291 | fsopt->rsize = CEPH_MOUNT_RSIZE_DEFAULT; | ||
| 292 | fsopt->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL); | ||
| 293 | fsopt->cap_release_safety = CEPH_CAP_RELEASE_SAFETY_DEFAULT; | ||
| 294 | fsopt->max_readdir = CEPH_MAX_READDIR_DEFAULT; | ||
| 295 | fsopt->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT; | ||
| 296 | fsopt->congestion_kb = default_congestion_kb(); | ||
| 297 | |||
| 298 | /* ip1[:port1][,ip2[:port2]...]:/subdir/in/fs */ | ||
| 299 | err = -EINVAL; | ||
| 300 | if (!dev_name) | ||
| 301 | goto out; | ||
| 302 | *path = strstr(dev_name, ":/"); | ||
| 303 | if (*path == NULL) { | ||
| 304 | pr_err("device name is missing path (no :/ in %s)\n", | ||
| 305 | dev_name); | ||
| 306 | goto out; | ||
| 307 | } | ||
| 308 | dev_name_end = *path; | ||
| 309 | dout("device name '%.*s'\n", (int)(dev_name_end - dev_name), dev_name); | ||
| 475 | 310 | ||
| 476 | /* path on server */ | 311 | /* path on server */ |
| 477 | *path += 2; | 312 | *path += 2; |
| 478 | dout("server path '%s'\n", *path); | 313 | dout("server path '%s'\n", *path); |
| 479 | 314 | ||
| 480 | /* parse mount options */ | 315 | err = ceph_parse_options(popt, options, dev_name, dev_name_end, |
| 481 | while ((c = strsep(&options, ",")) != NULL) { | 316 | parse_fsopt_token, (void *)fsopt); |
| 482 | int token, intval, ret; | 317 | if (err) |
| 483 | if (!*c) | 318 | goto out; |
| 484 | continue; | 319 | |
| 485 | err = -EINVAL; | 320 | /* success */ |
| 486 | token = match_token((char *)c, arg_tokens, argstr); | 321 | *pfsopt = fsopt; |
| 487 | if (token < 0) { | 322 | return 0; |
| 488 | pr_err("bad mount option at '%s'\n", c); | ||
| 489 | goto out; | ||
| 490 | } | ||
| 491 | if (token < Opt_last_int) { | ||
| 492 | ret = match_int(&argstr[0], &intval); | ||
| 493 | if (ret < 0) { | ||
| 494 | pr_err("bad mount option arg (not int) " | ||
| 495 | "at '%s'\n", c); | ||
| 496 | continue; | ||
| 497 | } | ||
| 498 | dout("got int token %d val %d\n", token, intval); | ||
| 499 | } else if (token > Opt_last_int && token < Opt_last_string) { | ||
| 500 | dout("got string token %d val %s\n", token, | ||
| 501 | argstr[0].from); | ||
| 502 | } else { | ||
| 503 | dout("got token %d\n", token); | ||
| 504 | } | ||
| 505 | switch (token) { | ||
| 506 | case Opt_ip: | ||
| 507 | err = ceph_parse_ips(argstr[0].from, | ||
| 508 | argstr[0].to, | ||
| 509 | &args->my_addr, | ||
| 510 | 1, NULL); | ||
| 511 | if (err < 0) | ||
| 512 | goto out; | ||
| 513 | args->flags |= CEPH_OPT_MYIP; | ||
| 514 | break; | ||
| 515 | |||
| 516 | case Opt_fsid: | ||
| 517 | err = parse_fsid(argstr[0].from, &args->fsid); | ||
| 518 | if (err == 0) | ||
| 519 | args->flags |= CEPH_OPT_FSID; | ||
| 520 | break; | ||
| 521 | case Opt_snapdirname: | ||
| 522 | kfree(args->snapdir_name); | ||
| 523 | args->snapdir_name = kstrndup(argstr[0].from, | ||
| 524 | argstr[0].to-argstr[0].from, | ||
| 525 | GFP_KERNEL); | ||
| 526 | break; | ||
| 527 | case Opt_name: | ||
| 528 | args->name = kstrndup(argstr[0].from, | ||
| 529 | argstr[0].to-argstr[0].from, | ||
| 530 | GFP_KERNEL); | ||
| 531 | break; | ||
| 532 | case Opt_secret: | ||
| 533 | args->secret = kstrndup(argstr[0].from, | ||
| 534 | argstr[0].to-argstr[0].from, | ||
| 535 | GFP_KERNEL); | ||
| 536 | break; | ||
| 537 | |||
| 538 | /* misc */ | ||
| 539 | case Opt_wsize: | ||
| 540 | args->wsize = intval; | ||
| 541 | break; | ||
| 542 | case Opt_rsize: | ||
| 543 | args->rsize = intval; | ||
| 544 | break; | ||
| 545 | case Opt_osdtimeout: | ||
| 546 | args->osd_timeout = intval; | ||
| 547 | break; | ||
| 548 | case Opt_osdkeepalivetimeout: | ||
| 549 | args->osd_keepalive_timeout = intval; | ||
| 550 | break; | ||
| 551 | case Opt_osd_idle_ttl: | ||
| 552 | args->osd_idle_ttl = intval; | ||
| 553 | break; | ||
| 554 | case Opt_mount_timeout: | ||
| 555 | args->mount_timeout = intval; | ||
| 556 | break; | ||
| 557 | case Opt_caps_wanted_delay_min: | ||
| 558 | args->caps_wanted_delay_min = intval; | ||
| 559 | break; | ||
| 560 | case Opt_caps_wanted_delay_max: | ||
| 561 | args->caps_wanted_delay_max = intval; | ||
| 562 | break; | ||
| 563 | case Opt_readdir_max_entries: | ||
| 564 | args->max_readdir = intval; | ||
| 565 | break; | ||
| 566 | case Opt_readdir_max_bytes: | ||
| 567 | args->max_readdir_bytes = intval; | ||
| 568 | break; | ||
| 569 | case Opt_congestion_kb: | ||
| 570 | args->congestion_kb = intval; | ||
| 571 | break; | ||
| 572 | |||
| 573 | case Opt_noshare: | ||
| 574 | args->flags |= CEPH_OPT_NOSHARE; | ||
| 575 | break; | ||
| 576 | |||
| 577 | case Opt_dirstat: | ||
| 578 | args->flags |= CEPH_OPT_DIRSTAT; | ||
| 579 | break; | ||
| 580 | case Opt_nodirstat: | ||
| 581 | args->flags &= ~CEPH_OPT_DIRSTAT; | ||
| 582 | break; | ||
| 583 | case Opt_rbytes: | ||
| 584 | args->flags |= CEPH_OPT_RBYTES; | ||
| 585 | break; | ||
| 586 | case Opt_norbytes: | ||
| 587 | args->flags &= ~CEPH_OPT_RBYTES; | ||
| 588 | break; | ||
| 589 | case Opt_nocrc: | ||
| 590 | args->flags |= CEPH_OPT_NOCRC; | ||
| 591 | break; | ||
| 592 | case Opt_noasyncreaddir: | ||
| 593 | args->flags |= CEPH_OPT_NOASYNCREADDIR; | ||
| 594 | break; | ||
| 595 | |||
| 596 | default: | ||
| 597 | BUG_ON(token); | ||
| 598 | } | ||
| 599 | } | ||
| 600 | return args; | ||
| 601 | 323 | ||
| 602 | out: | 324 | out: |
| 603 | kfree(args->mon_addr); | 325 | destroy_mount_options(fsopt); |
| 604 | kfree(args); | 326 | return err; |
| 605 | return ERR_PTR(err); | ||
| 606 | } | 327 | } |
| 607 | 328 | ||
| 608 | static void destroy_mount_args(struct ceph_mount_args *args) | 329 | /** |
| 330 | * ceph_show_options - Show mount options in /proc/mounts | ||
| 331 | * @m: seq_file to write to | ||
| 332 | * @mnt: mount descriptor | ||
| 333 | */ | ||
| 334 | static int ceph_show_options(struct seq_file *m, struct vfsmount *mnt) | ||
| 609 | { | 335 | { |
| 610 | dout("destroy_mount_args %p\n", args); | 336 | struct ceph_fs_client *fsc = ceph_sb_to_client(mnt->mnt_sb); |
| 611 | kfree(args->snapdir_name); | 337 | struct ceph_mount_options *fsopt = fsc->mount_options; |
| 612 | args->snapdir_name = NULL; | 338 | struct ceph_options *opt = fsc->client->options; |
| 613 | kfree(args->name); | 339 | |
| 614 | args->name = NULL; | 340 | if (opt->flags & CEPH_OPT_FSID) |
| 615 | kfree(args->secret); | 341 | seq_printf(m, ",fsid=%pU", &opt->fsid); |
| 616 | args->secret = NULL; | 342 | if (opt->flags & CEPH_OPT_NOSHARE) |
| 617 | kfree(args); | 343 | seq_puts(m, ",noshare"); |
| 344 | if (opt->flags & CEPH_OPT_NOCRC) | ||
| 345 | seq_puts(m, ",nocrc"); | ||
| 346 | |||
| 347 | if (opt->name) | ||
| 348 | seq_printf(m, ",name=%s", opt->name); | ||
| 349 | if (opt->secret) | ||
| 350 | seq_puts(m, ",secret=<hidden>"); | ||
| 351 | |||
| 352 | if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT) | ||
| 353 | seq_printf(m, ",mount_timeout=%d", opt->mount_timeout); | ||
| 354 | if (opt->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT) | ||
| 355 | seq_printf(m, ",osd_idle_ttl=%d", opt->osd_idle_ttl); | ||
| 356 | if (opt->osd_timeout != CEPH_OSD_TIMEOUT_DEFAULT) | ||
| 357 | seq_printf(m, ",osdtimeout=%d", opt->osd_timeout); | ||
| 358 | if (opt->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT) | ||
| 359 | seq_printf(m, ",osdkeepalivetimeout=%d", | ||
| 360 | opt->osd_keepalive_timeout); | ||
| 361 | |||
| 362 | if (fsopt->flags & CEPH_MOUNT_OPT_DIRSTAT) | ||
| 363 | seq_puts(m, ",dirstat"); | ||
| 364 | if ((fsopt->flags & CEPH_MOUNT_OPT_RBYTES) == 0) | ||
| 365 | seq_puts(m, ",norbytes"); | ||
| 366 | if (fsopt->flags & CEPH_MOUNT_OPT_NOASYNCREADDIR) | ||
| 367 | seq_puts(m, ",noasyncreaddir"); | ||
| 368 | |||
| 369 | if (fsopt->wsize) | ||
| 370 | seq_printf(m, ",wsize=%d", fsopt->wsize); | ||
| 371 | if (fsopt->rsize != CEPH_MOUNT_RSIZE_DEFAULT) | ||
| 372 | seq_printf(m, ",rsize=%d", fsopt->rsize); | ||
| 373 | if (fsopt->congestion_kb != default_congestion_kb()) | ||
| 374 | seq_printf(m, ",write_congestion_kb=%d", fsopt->congestion_kb); | ||
| 375 | if (fsopt->caps_wanted_delay_min != CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT) | ||
| 376 | seq_printf(m, ",caps_wanted_delay_min=%d", | ||
| 377 | fsopt->caps_wanted_delay_min); | ||
| 378 | if (fsopt->caps_wanted_delay_max != CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT) | ||
| 379 | seq_printf(m, ",caps_wanted_delay_max=%d", | ||
| 380 | fsopt->caps_wanted_delay_max); | ||
| 381 | if (fsopt->cap_release_safety != CEPH_CAP_RELEASE_SAFETY_DEFAULT) | ||
| 382 | seq_printf(m, ",cap_release_safety=%d", | ||
| 383 | fsopt->cap_release_safety); | ||
| 384 | if (fsopt->max_readdir != CEPH_MAX_READDIR_DEFAULT) | ||
| 385 | seq_printf(m, ",readdir_max_entries=%d", fsopt->max_readdir); | ||
| 386 | if (fsopt->max_readdir_bytes != CEPH_MAX_READDIR_BYTES_DEFAULT) | ||
| 387 | seq_printf(m, ",readdir_max_bytes=%d", fsopt->max_readdir_bytes); | ||
| 388 | if (strcmp(fsopt->snapdir_name, CEPH_SNAPDIRNAME_DEFAULT)) | ||
| 389 | seq_printf(m, ",snapdirname=%s", fsopt->snapdir_name); | ||
| 390 | return 0; | ||
| 618 | } | 391 | } |
| 619 | 392 | ||
| 620 | /* | 393 | /* |
| 621 | * create a fresh client instance | 394 | * handle any mon messages the standard library doesn't understand. |
| 395 | * return error if we don't either. | ||
| 622 | */ | 396 | */ |
| 623 | static struct ceph_client *ceph_create_client(struct ceph_mount_args *args) | 397 | static int extra_mon_dispatch(struct ceph_client *client, struct ceph_msg *msg) |
| 624 | { | 398 | { |
| 625 | struct ceph_client *client; | 399 | struct ceph_fs_client *fsc = client->private; |
| 400 | int type = le16_to_cpu(msg->hdr.type); | ||
| 401 | |||
| 402 | switch (type) { | ||
| 403 | case CEPH_MSG_MDS_MAP: | ||
| 404 | ceph_mdsc_handle_map(fsc->mdsc, msg); | ||
| 405 | return 0; | ||
| 406 | |||
| 407 | default: | ||
| 408 | return -1; | ||
| 409 | } | ||
| 410 | } | ||
| 411 | |||
| 412 | /* | ||
| 413 | * create a new fs client | ||
| 414 | */ | ||
| 415 | struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt, | ||
| 416 | struct ceph_options *opt) | ||
| 417 | { | ||
| 418 | struct ceph_fs_client *fsc; | ||
| 626 | int err = -ENOMEM; | 419 | int err = -ENOMEM; |
| 627 | 420 | ||
| 628 | client = kzalloc(sizeof(*client), GFP_KERNEL); | 421 | fsc = kzalloc(sizeof(*fsc), GFP_KERNEL); |
| 629 | if (client == NULL) | 422 | if (!fsc) |
| 630 | return ERR_PTR(-ENOMEM); | 423 | return ERR_PTR(-ENOMEM); |
| 631 | 424 | ||
| 632 | mutex_init(&client->mount_mutex); | 425 | fsc->client = ceph_create_client(opt, fsc); |
| 633 | 426 | if (IS_ERR(fsc->client)) { | |
| 634 | init_waitqueue_head(&client->auth_wq); | 427 | err = PTR_ERR(fsc->client); |
| 428 | goto fail; | ||
| 429 | } | ||
| 430 | fsc->client->extra_mon_dispatch = extra_mon_dispatch; | ||
| 431 | fsc->client->supported_features |= CEPH_FEATURE_FLOCK; | ||
| 432 | fsc->client->monc.want_mdsmap = 1; | ||
| 635 | 433 | ||
| 636 | client->sb = NULL; | 434 | fsc->mount_options = fsopt; |
| 637 | client->mount_state = CEPH_MOUNT_MOUNTING; | ||
| 638 | client->mount_args = args; | ||
| 639 | 435 | ||
| 640 | client->msgr = NULL; | 436 | fsc->sb = NULL; |
| 437 | fsc->mount_state = CEPH_MOUNT_MOUNTING; | ||
| 641 | 438 | ||
| 642 | client->auth_err = 0; | 439 | atomic_long_set(&fsc->writeback_count, 0); |
| 643 | atomic_long_set(&client->writeback_count, 0); | ||
| 644 | 440 | ||
| 645 | err = bdi_init(&client->backing_dev_info); | 441 | err = bdi_init(&fsc->backing_dev_info); |
| 646 | if (err < 0) | 442 | if (err < 0) |
| 647 | goto fail; | 443 | goto fail_client; |
| 648 | 444 | ||
| 649 | err = -ENOMEM; | 445 | err = -ENOMEM; |
| 650 | client->wb_wq = create_workqueue("ceph-writeback"); | 446 | fsc->wb_wq = create_workqueue("ceph-writeback"); |
| 651 | if (client->wb_wq == NULL) | 447 | if (fsc->wb_wq == NULL) |
| 652 | goto fail_bdi; | 448 | goto fail_bdi; |
| 653 | client->pg_inv_wq = create_singlethread_workqueue("ceph-pg-invalid"); | 449 | fsc->pg_inv_wq = create_singlethread_workqueue("ceph-pg-invalid"); |
| 654 | if (client->pg_inv_wq == NULL) | 450 | if (fsc->pg_inv_wq == NULL) |
| 655 | goto fail_wb_wq; | 451 | goto fail_wb_wq; |
| 656 | client->trunc_wq = create_singlethread_workqueue("ceph-trunc"); | 452 | fsc->trunc_wq = create_singlethread_workqueue("ceph-trunc"); |
| 657 | if (client->trunc_wq == NULL) | 453 | if (fsc->trunc_wq == NULL) |
| 658 | goto fail_pg_inv_wq; | 454 | goto fail_pg_inv_wq; |
| 659 | 455 | ||
| 660 | /* set up mempools */ | 456 | /* set up mempools */ |
| 661 | err = -ENOMEM; | 457 | err = -ENOMEM; |
| 662 | client->wb_pagevec_pool = mempool_create_kmalloc_pool(10, | 458 | fsc->wb_pagevec_pool = mempool_create_kmalloc_pool(10, |
| 663 | client->mount_args->wsize >> PAGE_CACHE_SHIFT); | 459 | fsc->mount_options->wsize >> PAGE_CACHE_SHIFT); |
| 664 | if (!client->wb_pagevec_pool) | 460 | if (!fsc->wb_pagevec_pool) |
| 665 | goto fail_trunc_wq; | 461 | goto fail_trunc_wq; |
| 666 | 462 | ||
| 667 | /* caps */ | 463 | /* caps */ |
| 668 | client->min_caps = args->max_readdir; | 464 | fsc->min_caps = fsopt->max_readdir; |
| 465 | |||
| 466 | return fsc; | ||
| 669 | 467 | ||
| 670 | /* subsystems */ | ||
| 671 | err = ceph_monc_init(&client->monc, client); | ||
| 672 | if (err < 0) | ||
| 673 | goto fail_mempool; | ||
| 674 | err = ceph_osdc_init(&client->osdc, client); | ||
| 675 | if (err < 0) | ||
| 676 | goto fail_monc; | ||
| 677 | err = ceph_mdsc_init(&client->mdsc, client); | ||
| 678 | if (err < 0) | ||
| 679 | goto fail_osdc; | ||
| 680 | return client; | ||
| 681 | |||
| 682 | fail_osdc: | ||
| 683 | ceph_osdc_stop(&client->osdc); | ||
| 684 | fail_monc: | ||
| 685 | ceph_monc_stop(&client->monc); | ||
| 686 | fail_mempool: | ||
| 687 | mempool_destroy(client->wb_pagevec_pool); | ||
| 688 | fail_trunc_wq: | 468 | fail_trunc_wq: |
| 689 | destroy_workqueue(client->trunc_wq); | 469 | destroy_workqueue(fsc->trunc_wq); |
| 690 | fail_pg_inv_wq: | 470 | fail_pg_inv_wq: |
| 691 | destroy_workqueue(client->pg_inv_wq); | 471 | destroy_workqueue(fsc->pg_inv_wq); |
| 692 | fail_wb_wq: | 472 | fail_wb_wq: |
| 693 | destroy_workqueue(client->wb_wq); | 473 | destroy_workqueue(fsc->wb_wq); |
| 694 | fail_bdi: | 474 | fail_bdi: |
| 695 | bdi_destroy(&client->backing_dev_info); | 475 | bdi_destroy(&fsc->backing_dev_info); |
| 476 | fail_client: | ||
| 477 | ceph_destroy_client(fsc->client); | ||
| 696 | fail: | 478 | fail: |
| 697 | kfree(client); | 479 | kfree(fsc); |
| 698 | return ERR_PTR(err); | 480 | return ERR_PTR(err); |
| 699 | } | 481 | } |
| 700 | 482 | ||
| 701 | static void ceph_destroy_client(struct ceph_client *client) | 483 | void destroy_fs_client(struct ceph_fs_client *fsc) |
| 702 | { | 484 | { |
| 703 | dout("destroy_client %p\n", client); | 485 | dout("destroy_fs_client %p\n", fsc); |
| 704 | 486 | ||
| 705 | /* unmount */ | 487 | destroy_workqueue(fsc->wb_wq); |
| 706 | ceph_mdsc_stop(&client->mdsc); | 488 | destroy_workqueue(fsc->pg_inv_wq); |
| 707 | ceph_osdc_stop(&client->osdc); | 489 | destroy_workqueue(fsc->trunc_wq); |
| 708 | 490 | ||
| 709 | /* | 491 | bdi_destroy(&fsc->backing_dev_info); |
| 710 | * make sure mds and osd connections close out before destroying | ||
| 711 | * the auth module, which is needed to free those connections' | ||
| 712 | * ceph_authorizers. | ||
| 713 | */ | ||
| 714 | ceph_msgr_flush(); | ||
| 715 | |||
| 716 | ceph_monc_stop(&client->monc); | ||
| 717 | 492 | ||
| 718 | ceph_debugfs_client_cleanup(client); | 493 | mempool_destroy(fsc->wb_pagevec_pool); |
| 719 | destroy_workqueue(client->wb_wq); | ||
| 720 | destroy_workqueue(client->pg_inv_wq); | ||
| 721 | destroy_workqueue(client->trunc_wq); | ||
| 722 | 494 | ||
| 723 | bdi_destroy(&client->backing_dev_info); | 495 | destroy_mount_options(fsc->mount_options); |
| 724 | 496 | ||
| 725 | if (client->msgr) | 497 | ceph_fs_debugfs_cleanup(fsc); |
| 726 | ceph_messenger_destroy(client->msgr); | ||
| 727 | mempool_destroy(client->wb_pagevec_pool); | ||
| 728 | 498 | ||
| 729 | destroy_mount_args(client->mount_args); | 499 | ceph_destroy_client(fsc->client); |
| 730 | 500 | ||
| 731 | kfree(client); | 501 | kfree(fsc); |
| 732 | dout("destroy_client %p done\n", client); | 502 | dout("destroy_fs_client %p done\n", fsc); |
| 733 | } | 503 | } |
| 734 | 504 | ||
| 735 | /* | 505 | /* |
| 736 | * Initially learn our fsid, or verify an fsid matches. | 506 | * caches |
| 737 | */ | 507 | */ |
| 738 | int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid) | 508 | struct kmem_cache *ceph_inode_cachep; |
| 509 | struct kmem_cache *ceph_cap_cachep; | ||
| 510 | struct kmem_cache *ceph_dentry_cachep; | ||
| 511 | struct kmem_cache *ceph_file_cachep; | ||
| 512 | |||
| 513 | static void ceph_inode_init_once(void *foo) | ||
| 739 | { | 514 | { |
| 740 | if (client->have_fsid) { | 515 | struct ceph_inode_info *ci = foo; |
| 741 | if (ceph_fsid_compare(&client->fsid, fsid)) { | 516 | inode_init_once(&ci->vfs_inode); |
| 742 | pr_err("bad fsid, had %pU got %pU", | 517 | } |
| 743 | &client->fsid, fsid); | 518 | |
| 744 | return -1; | 519 | static int __init init_caches(void) |
| 745 | } | 520 | { |
| 746 | } else { | 521 | ceph_inode_cachep = kmem_cache_create("ceph_inode_info", |
| 747 | pr_info("client%lld fsid %pU\n", client->monc.auth->global_id, | 522 | sizeof(struct ceph_inode_info), |
| 748 | fsid); | 523 | __alignof__(struct ceph_inode_info), |
| 749 | memcpy(&client->fsid, fsid, sizeof(*fsid)); | 524 | (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD), |
| 750 | ceph_debugfs_client_init(client); | 525 | ceph_inode_init_once); |
| 751 | client->have_fsid = true; | 526 | if (ceph_inode_cachep == NULL) |
| 752 | } | 527 | return -ENOMEM; |
| 528 | |||
| 529 | ceph_cap_cachep = KMEM_CACHE(ceph_cap, | ||
| 530 | SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD); | ||
| 531 | if (ceph_cap_cachep == NULL) | ||
| 532 | goto bad_cap; | ||
| 533 | |||
| 534 | ceph_dentry_cachep = KMEM_CACHE(ceph_dentry_info, | ||
| 535 | SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD); | ||
| 536 | if (ceph_dentry_cachep == NULL) | ||
| 537 | goto bad_dentry; | ||
| 538 | |||
| 539 | ceph_file_cachep = KMEM_CACHE(ceph_file_info, | ||
| 540 | SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD); | ||
| 541 | if (ceph_file_cachep == NULL) | ||
| 542 | goto bad_file; | ||
| 543 | |||
| 753 | return 0; | 544 | return 0; |
| 545 | |||
| 546 | bad_file: | ||
| 547 | kmem_cache_destroy(ceph_dentry_cachep); | ||
| 548 | bad_dentry: | ||
| 549 | kmem_cache_destroy(ceph_cap_cachep); | ||
| 550 | bad_cap: | ||
| 551 | kmem_cache_destroy(ceph_inode_cachep); | ||
| 552 | return -ENOMEM; | ||
| 754 | } | 553 | } |
| 755 | 554 | ||
| 555 | static void destroy_caches(void) | ||
| 556 | { | ||
| 557 | kmem_cache_destroy(ceph_inode_cachep); | ||
| 558 | kmem_cache_destroy(ceph_cap_cachep); | ||
| 559 | kmem_cache_destroy(ceph_dentry_cachep); | ||
| 560 | kmem_cache_destroy(ceph_file_cachep); | ||
| 561 | } | ||
| 562 | |||
| 563 | |||
| 756 | /* | 564 | /* |
| 757 | * true if we have the mon map (and have thus joined the cluster) | 565 | * ceph_umount_begin - initiate forced umount. Tear down down the |
| 566 | * mount, skipping steps that may hang while waiting for server(s). | ||
| 758 | */ | 567 | */ |
| 759 | static int have_mon_and_osd_map(struct ceph_client *client) | 568 | static void ceph_umount_begin(struct super_block *sb) |
| 760 | { | 569 | { |
| 761 | return client->monc.monmap && client->monc.monmap->epoch && | 570 | struct ceph_fs_client *fsc = ceph_sb_to_client(sb); |
| 762 | client->osdc.osdmap && client->osdc.osdmap->epoch; | 571 | |
| 572 | dout("ceph_umount_begin - starting forced umount\n"); | ||
| 573 | if (!fsc) | ||
| 574 | return; | ||
| 575 | fsc->mount_state = CEPH_MOUNT_SHUTDOWN; | ||
| 576 | return; | ||
| 763 | } | 577 | } |
| 764 | 578 | ||
| 579 | static const struct super_operations ceph_super_ops = { | ||
| 580 | .alloc_inode = ceph_alloc_inode, | ||
| 581 | .destroy_inode = ceph_destroy_inode, | ||
| 582 | .write_inode = ceph_write_inode, | ||
| 583 | .sync_fs = ceph_sync_fs, | ||
| 584 | .put_super = ceph_put_super, | ||
| 585 | .show_options = ceph_show_options, | ||
| 586 | .statfs = ceph_statfs, | ||
| 587 | .umount_begin = ceph_umount_begin, | ||
| 588 | }; | ||
| 589 | |||
| 765 | /* | 590 | /* |
| 766 | * Bootstrap mount by opening the root directory. Note the mount | 591 | * Bootstrap mount by opening the root directory. Note the mount |
| 767 | * @started time from caller, and time out if this takes too long. | 592 | * @started time from caller, and time out if this takes too long. |
| 768 | */ | 593 | */ |
| 769 | static struct dentry *open_root_dentry(struct ceph_client *client, | 594 | static struct dentry *open_root_dentry(struct ceph_fs_client *fsc, |
| 770 | const char *path, | 595 | const char *path, |
| 771 | unsigned long started) | 596 | unsigned long started) |
| 772 | { | 597 | { |
| 773 | struct ceph_mds_client *mdsc = &client->mdsc; | 598 | struct ceph_mds_client *mdsc = fsc->mdsc; |
| 774 | struct ceph_mds_request *req = NULL; | 599 | struct ceph_mds_request *req = NULL; |
| 775 | int err; | 600 | int err; |
| 776 | struct dentry *root; | 601 | struct dentry *root; |
| @@ -784,14 +609,14 @@ static struct dentry *open_root_dentry(struct ceph_client *client, | |||
| 784 | req->r_ino1.ino = CEPH_INO_ROOT; | 609 | req->r_ino1.ino = CEPH_INO_ROOT; |
| 785 | req->r_ino1.snap = CEPH_NOSNAP; | 610 | req->r_ino1.snap = CEPH_NOSNAP; |
| 786 | req->r_started = started; | 611 | req->r_started = started; |
| 787 | req->r_timeout = client->mount_args->mount_timeout * HZ; | 612 | req->r_timeout = fsc->client->options->mount_timeout * HZ; |
| 788 | req->r_args.getattr.mask = cpu_to_le32(CEPH_STAT_CAP_INODE); | 613 | req->r_args.getattr.mask = cpu_to_le32(CEPH_STAT_CAP_INODE); |
| 789 | req->r_num_caps = 2; | 614 | req->r_num_caps = 2; |
| 790 | err = ceph_mdsc_do_request(mdsc, NULL, req); | 615 | err = ceph_mdsc_do_request(mdsc, NULL, req); |
| 791 | if (err == 0) { | 616 | if (err == 0) { |
| 792 | dout("open_root_inode success\n"); | 617 | dout("open_root_inode success\n"); |
| 793 | if (ceph_ino(req->r_target_inode) == CEPH_INO_ROOT && | 618 | if (ceph_ino(req->r_target_inode) == CEPH_INO_ROOT && |
| 794 | client->sb->s_root == NULL) | 619 | fsc->sb->s_root == NULL) |
| 795 | root = d_alloc_root(req->r_target_inode); | 620 | root = d_alloc_root(req->r_target_inode); |
| 796 | else | 621 | else |
| 797 | root = d_obtain_alias(req->r_target_inode); | 622 | root = d_obtain_alias(req->r_target_inode); |
| @@ -804,105 +629,86 @@ static struct dentry *open_root_dentry(struct ceph_client *client, | |||
| 804 | return root; | 629 | return root; |
| 805 | } | 630 | } |
| 806 | 631 | ||
| 632 | |||
| 633 | |||
| 634 | |||
| 807 | /* | 635 | /* |
| 808 | * mount: join the ceph cluster, and open root directory. | 636 | * mount: join the ceph cluster, and open root directory. |
| 809 | */ | 637 | */ |
| 810 | static int ceph_mount(struct ceph_client *client, struct vfsmount *mnt, | 638 | static int ceph_mount(struct ceph_fs_client *fsc, struct vfsmount *mnt, |
| 811 | const char *path) | 639 | const char *path) |
| 812 | { | 640 | { |
| 813 | struct ceph_entity_addr *myaddr = NULL; | ||
| 814 | int err; | 641 | int err; |
| 815 | unsigned long timeout = client->mount_args->mount_timeout * HZ; | ||
| 816 | unsigned long started = jiffies; /* note the start time */ | 642 | unsigned long started = jiffies; /* note the start time */ |
| 817 | struct dentry *root; | 643 | struct dentry *root; |
| 644 | int first = 0; /* first vfsmount for this super_block */ | ||
| 818 | 645 | ||
| 819 | dout("mount start\n"); | 646 | dout("mount start\n"); |
| 820 | mutex_lock(&client->mount_mutex); | 647 | mutex_lock(&fsc->client->mount_mutex); |
| 821 | |||
| 822 | /* initialize the messenger */ | ||
| 823 | if (client->msgr == NULL) { | ||
| 824 | if (ceph_test_opt(client, MYIP)) | ||
| 825 | myaddr = &client->mount_args->my_addr; | ||
| 826 | client->msgr = ceph_messenger_create(myaddr); | ||
| 827 | if (IS_ERR(client->msgr)) { | ||
| 828 | err = PTR_ERR(client->msgr); | ||
| 829 | client->msgr = NULL; | ||
| 830 | goto out; | ||
| 831 | } | ||
| 832 | client->msgr->nocrc = ceph_test_opt(client, NOCRC); | ||
| 833 | } | ||
| 834 | 648 | ||
| 835 | /* open session, and wait for mon, mds, and osd maps */ | 649 | err = __ceph_open_session(fsc->client, started); |
| 836 | err = ceph_monc_open_session(&client->monc); | ||
| 837 | if (err < 0) | 650 | if (err < 0) |
| 838 | goto out; | 651 | goto out; |
| 839 | 652 | ||
| 840 | while (!have_mon_and_osd_map(client)) { | ||
| 841 | err = -EIO; | ||
| 842 | if (timeout && time_after_eq(jiffies, started + timeout)) | ||
| 843 | goto out; | ||
| 844 | |||
| 845 | /* wait */ | ||
| 846 | dout("mount waiting for mon_map\n"); | ||
| 847 | err = wait_event_interruptible_timeout(client->auth_wq, | ||
| 848 | have_mon_and_osd_map(client) || (client->auth_err < 0), | ||
| 849 | timeout); | ||
| 850 | if (err == -EINTR || err == -ERESTARTSYS) | ||
| 851 | goto out; | ||
| 852 | if (client->auth_err < 0) { | ||
| 853 | err = client->auth_err; | ||
| 854 | goto out; | ||
| 855 | } | ||
| 856 | } | ||
| 857 | |||
| 858 | dout("mount opening root\n"); | 653 | dout("mount opening root\n"); |
| 859 | root = open_root_dentry(client, "", started); | 654 | root = open_root_dentry(fsc, "", started); |
| 860 | if (IS_ERR(root)) { | 655 | if (IS_ERR(root)) { |
| 861 | err = PTR_ERR(root); | 656 | err = PTR_ERR(root); |
| 862 | goto out; | 657 | goto out; |
| 863 | } | 658 | } |
| 864 | if (client->sb->s_root) | 659 | if (fsc->sb->s_root) { |
| 865 | dput(root); | 660 | dput(root); |
| 866 | else | 661 | } else { |
| 867 | client->sb->s_root = root; | 662 | fsc->sb->s_root = root; |
| 663 | first = 1; | ||
| 664 | |||
| 665 | err = ceph_fs_debugfs_init(fsc); | ||
| 666 | if (err < 0) | ||
| 667 | goto fail; | ||
| 668 | } | ||
| 868 | 669 | ||
| 869 | if (path[0] == 0) { | 670 | if (path[0] == 0) { |
| 870 | dget(root); | 671 | dget(root); |
| 871 | } else { | 672 | } else { |
| 872 | dout("mount opening base mountpoint\n"); | 673 | dout("mount opening base mountpoint\n"); |
| 873 | root = open_root_dentry(client, path, started); | 674 | root = open_root_dentry(fsc, path, started); |
| 874 | if (IS_ERR(root)) { | 675 | if (IS_ERR(root)) { |
| 875 | err = PTR_ERR(root); | 676 | err = PTR_ERR(root); |
| 876 | dput(client->sb->s_root); | 677 | goto fail; |
| 877 | client->sb->s_root = NULL; | ||
| 878 | goto out; | ||
| 879 | } | 678 | } |
| 880 | } | 679 | } |
| 881 | 680 | ||
| 882 | mnt->mnt_root = root; | 681 | mnt->mnt_root = root; |
| 883 | mnt->mnt_sb = client->sb; | 682 | mnt->mnt_sb = fsc->sb; |
| 884 | 683 | ||
| 885 | client->mount_state = CEPH_MOUNT_MOUNTED; | 684 | fsc->mount_state = CEPH_MOUNT_MOUNTED; |
| 886 | dout("mount success\n"); | 685 | dout("mount success\n"); |
| 887 | err = 0; | 686 | err = 0; |
| 888 | 687 | ||
| 889 | out: | 688 | out: |
| 890 | mutex_unlock(&client->mount_mutex); | 689 | mutex_unlock(&fsc->client->mount_mutex); |
| 891 | return err; | 690 | return err; |
| 691 | |||
| 692 | fail: | ||
| 693 | if (first) { | ||
| 694 | dput(fsc->sb->s_root); | ||
| 695 | fsc->sb->s_root = NULL; | ||
| 696 | } | ||
| 697 | goto out; | ||
| 892 | } | 698 | } |
| 893 | 699 | ||
| 894 | static int ceph_set_super(struct super_block *s, void *data) | 700 | static int ceph_set_super(struct super_block *s, void *data) |
| 895 | { | 701 | { |
| 896 | struct ceph_client *client = data; | 702 | struct ceph_fs_client *fsc = data; |
| 897 | int ret; | 703 | int ret; |
| 898 | 704 | ||
| 899 | dout("set_super %p data %p\n", s, data); | 705 | dout("set_super %p data %p\n", s, data); |
| 900 | 706 | ||
| 901 | s->s_flags = client->mount_args->sb_flags; | 707 | s->s_flags = fsc->mount_options->sb_flags; |
| 902 | s->s_maxbytes = 1ULL << 40; /* temp value until we get mdsmap */ | 708 | s->s_maxbytes = 1ULL << 40; /* temp value until we get mdsmap */ |
| 903 | 709 | ||
| 904 | s->s_fs_info = client; | 710 | s->s_fs_info = fsc; |
| 905 | client->sb = s; | 711 | fsc->sb = s; |
| 906 | 712 | ||
| 907 | s->s_op = &ceph_super_ops; | 713 | s->s_op = &ceph_super_ops; |
| 908 | s->s_export_op = &ceph_export_ops; | 714 | s->s_export_op = &ceph_export_ops; |
| @@ -917,7 +723,7 @@ static int ceph_set_super(struct super_block *s, void *data) | |||
| 917 | 723 | ||
| 918 | fail: | 724 | fail: |
| 919 | s->s_fs_info = NULL; | 725 | s->s_fs_info = NULL; |
| 920 | client->sb = NULL; | 726 | fsc->sb = NULL; |
| 921 | return ret; | 727 | return ret; |
| 922 | } | 728 | } |
| 923 | 729 | ||
| @@ -926,30 +732,23 @@ fail: | |||
| 926 | */ | 732 | */ |
| 927 | static int ceph_compare_super(struct super_block *sb, void *data) | 733 | static int ceph_compare_super(struct super_block *sb, void *data) |
| 928 | { | 734 | { |
| 929 | struct ceph_client *new = data; | 735 | struct ceph_fs_client *new = data; |
| 930 | struct ceph_mount_args *args = new->mount_args; | 736 | struct ceph_mount_options *fsopt = new->mount_options; |
| 931 | struct ceph_client *other = ceph_sb_to_client(sb); | 737 | struct ceph_options *opt = new->client->options; |
| 932 | int i; | 738 | struct ceph_fs_client *other = ceph_sb_to_client(sb); |
| 933 | 739 | ||
| 934 | dout("ceph_compare_super %p\n", sb); | 740 | dout("ceph_compare_super %p\n", sb); |
| 935 | if (args->flags & CEPH_OPT_FSID) { | 741 | |
| 936 | if (ceph_fsid_compare(&args->fsid, &other->fsid)) { | 742 | if (compare_mount_options(fsopt, opt, other)) { |
| 937 | dout("fsid doesn't match\n"); | 743 | dout("monitor(s)/mount options don't match\n"); |
| 938 | return 0; | 744 | return 0; |
| 939 | } | ||
| 940 | } else { | ||
| 941 | /* do we share (a) monitor? */ | ||
| 942 | for (i = 0; i < new->monc.monmap->num_mon; i++) | ||
| 943 | if (ceph_monmap_contains(other->monc.monmap, | ||
| 944 | &new->monc.monmap->mon_inst[i].addr)) | ||
| 945 | break; | ||
| 946 | if (i == new->monc.monmap->num_mon) { | ||
| 947 | dout("mon ip not part of monmap\n"); | ||
| 948 | return 0; | ||
| 949 | } | ||
| 950 | dout("mon ip matches existing sb %p\n", sb); | ||
| 951 | } | 745 | } |
| 952 | if (args->sb_flags != other->mount_args->sb_flags) { | 746 | if ((opt->flags & CEPH_OPT_FSID) && |
| 747 | ceph_fsid_compare(&opt->fsid, &other->client->fsid)) { | ||
| 748 | dout("fsid doesn't match\n"); | ||
| 749 | return 0; | ||
| 750 | } | ||
| 751 | if (fsopt->sb_flags != other->mount_options->sb_flags) { | ||
| 953 | dout("flags differ\n"); | 752 | dout("flags differ\n"); |
| 954 | return 0; | 753 | return 0; |
| 955 | } | 754 | } |
| @@ -961,19 +760,20 @@ static int ceph_compare_super(struct super_block *sb, void *data) | |||
| 961 | */ | 760 | */ |
| 962 | static atomic_long_t bdi_seq = ATOMIC_LONG_INIT(0); | 761 | static atomic_long_t bdi_seq = ATOMIC_LONG_INIT(0); |
| 963 | 762 | ||
| 964 | static int ceph_register_bdi(struct super_block *sb, struct ceph_client *client) | 763 | static int ceph_register_bdi(struct super_block *sb, |
| 764 | struct ceph_fs_client *fsc) | ||
| 965 | { | 765 | { |
| 966 | int err; | 766 | int err; |
| 967 | 767 | ||
| 968 | /* set ra_pages based on rsize mount option? */ | 768 | /* set ra_pages based on rsize mount option? */ |
| 969 | if (client->mount_args->rsize >= PAGE_CACHE_SIZE) | 769 | if (fsc->mount_options->rsize >= PAGE_CACHE_SIZE) |
| 970 | client->backing_dev_info.ra_pages = | 770 | fsc->backing_dev_info.ra_pages = |
| 971 | (client->mount_args->rsize + PAGE_CACHE_SIZE - 1) | 771 | (fsc->mount_options->rsize + PAGE_CACHE_SIZE - 1) |
| 972 | >> PAGE_SHIFT; | 772 | >> PAGE_SHIFT; |
| 973 | err = bdi_register(&client->backing_dev_info, NULL, "ceph-%d", | 773 | err = bdi_register(&fsc->backing_dev_info, NULL, "ceph-%d", |
| 974 | atomic_long_inc_return(&bdi_seq)); | 774 | atomic_long_inc_return(&bdi_seq)); |
| 975 | if (!err) | 775 | if (!err) |
| 976 | sb->s_bdi = &client->backing_dev_info; | 776 | sb->s_bdi = &fsc->backing_dev_info; |
| 977 | return err; | 777 | return err; |
| 978 | } | 778 | } |
| 979 | 779 | ||
| @@ -982,46 +782,52 @@ static int ceph_get_sb(struct file_system_type *fs_type, | |||
| 982 | struct vfsmount *mnt) | 782 | struct vfsmount *mnt) |
| 983 | { | 783 | { |
| 984 | struct super_block *sb; | 784 | struct super_block *sb; |
| 985 | struct ceph_client *client; | 785 | struct ceph_fs_client *fsc; |
| 986 | int err; | 786 | int err; |
| 987 | int (*compare_super)(struct super_block *, void *) = ceph_compare_super; | 787 | int (*compare_super)(struct super_block *, void *) = ceph_compare_super; |
| 988 | const char *path = NULL; | 788 | const char *path = NULL; |
| 989 | struct ceph_mount_args *args; | 789 | struct ceph_mount_options *fsopt = NULL; |
| 790 | struct ceph_options *opt = NULL; | ||
| 990 | 791 | ||
| 991 | dout("ceph_get_sb\n"); | 792 | dout("ceph_get_sb\n"); |
| 992 | args = parse_mount_args(flags, data, dev_name, &path); | 793 | err = parse_mount_options(&fsopt, &opt, flags, data, dev_name, &path); |
| 993 | if (IS_ERR(args)) { | 794 | if (err < 0) |
| 994 | err = PTR_ERR(args); | ||
| 995 | goto out_final; | 795 | goto out_final; |
| 996 | } | ||
| 997 | 796 | ||
| 998 | /* create client (which we may/may not use) */ | 797 | /* create client (which we may/may not use) */ |
| 999 | client = ceph_create_client(args); | 798 | fsc = create_fs_client(fsopt, opt); |
| 1000 | if (IS_ERR(client)) { | 799 | if (IS_ERR(fsc)) { |
| 1001 | err = PTR_ERR(client); | 800 | err = PTR_ERR(fsc); |
| 801 | kfree(fsopt); | ||
| 802 | kfree(opt); | ||
| 1002 | goto out_final; | 803 | goto out_final; |
| 1003 | } | 804 | } |
| 1004 | 805 | ||
| 1005 | if (client->mount_args->flags & CEPH_OPT_NOSHARE) | 806 | err = ceph_mdsc_init(fsc); |
| 807 | if (err < 0) | ||
| 808 | goto out; | ||
| 809 | |||
| 810 | if (ceph_test_opt(fsc->client, NOSHARE)) | ||
| 1006 | compare_super = NULL; | 811 | compare_super = NULL; |
| 1007 | sb = sget(fs_type, compare_super, ceph_set_super, client); | 812 | sb = sget(fs_type, compare_super, ceph_set_super, fsc); |
| 1008 | if (IS_ERR(sb)) { | 813 | if (IS_ERR(sb)) { |
| 1009 | err = PTR_ERR(sb); | 814 | err = PTR_ERR(sb); |
| 1010 | goto out; | 815 | goto out; |
| 1011 | } | 816 | } |
| 1012 | 817 | ||
| 1013 | if (ceph_sb_to_client(sb) != client) { | 818 | if (ceph_sb_to_client(sb) != fsc) { |
| 1014 | ceph_destroy_client(client); | 819 | ceph_mdsc_destroy(fsc); |
| 1015 | client = ceph_sb_to_client(sb); | 820 | destroy_fs_client(fsc); |
| 1016 | dout("get_sb got existing client %p\n", client); | 821 | fsc = ceph_sb_to_client(sb); |
| 822 | dout("get_sb got existing client %p\n", fsc); | ||
| 1017 | } else { | 823 | } else { |
| 1018 | dout("get_sb using new client %p\n", client); | 824 | dout("get_sb using new client %p\n", fsc); |
| 1019 | err = ceph_register_bdi(sb, client); | 825 | err = ceph_register_bdi(sb, fsc); |
| 1020 | if (err < 0) | 826 | if (err < 0) |
| 1021 | goto out_splat; | 827 | goto out_splat; |
| 1022 | } | 828 | } |
| 1023 | 829 | ||
| 1024 | err = ceph_mount(client, mnt, path); | 830 | err = ceph_mount(fsc, mnt, path); |
| 1025 | if (err < 0) | 831 | if (err < 0) |
| 1026 | goto out_splat; | 832 | goto out_splat; |
| 1027 | dout("root %p inode %p ino %llx.%llx\n", mnt->mnt_root, | 833 | dout("root %p inode %p ino %llx.%llx\n", mnt->mnt_root, |
| @@ -1029,12 +835,13 @@ static int ceph_get_sb(struct file_system_type *fs_type, | |||
| 1029 | return 0; | 835 | return 0; |
| 1030 | 836 | ||
| 1031 | out_splat: | 837 | out_splat: |
| 1032 | ceph_mdsc_close_sessions(&client->mdsc); | 838 | ceph_mdsc_close_sessions(fsc->mdsc); |
| 1033 | deactivate_locked_super(sb); | 839 | deactivate_locked_super(sb); |
| 1034 | goto out_final; | 840 | goto out_final; |
| 1035 | 841 | ||
| 1036 | out: | 842 | out: |
| 1037 | ceph_destroy_client(client); | 843 | ceph_mdsc_destroy(fsc); |
| 844 | destroy_fs_client(fsc); | ||
| 1038 | out_final: | 845 | out_final: |
| 1039 | dout("ceph_get_sb fail %d\n", err); | 846 | dout("ceph_get_sb fail %d\n", err); |
| 1040 | return err; | 847 | return err; |
| @@ -1042,11 +849,12 @@ out_final: | |||
| 1042 | 849 | ||
| 1043 | static void ceph_kill_sb(struct super_block *s) | 850 | static void ceph_kill_sb(struct super_block *s) |
| 1044 | { | 851 | { |
| 1045 | struct ceph_client *client = ceph_sb_to_client(s); | 852 | struct ceph_fs_client *fsc = ceph_sb_to_client(s); |
| 1046 | dout("kill_sb %p\n", s); | 853 | dout("kill_sb %p\n", s); |
| 1047 | ceph_mdsc_pre_umount(&client->mdsc); | 854 | ceph_mdsc_pre_umount(fsc->mdsc); |
| 1048 | kill_anon_super(s); /* will call put_super after sb is r/o */ | 855 | kill_anon_super(s); /* will call put_super after sb is r/o */ |
| 1049 | ceph_destroy_client(client); | 856 | ceph_mdsc_destroy(fsc); |
| 857 | destroy_fs_client(fsc); | ||
| 1050 | } | 858 | } |
| 1051 | 859 | ||
| 1052 | static struct file_system_type ceph_fs_type = { | 860 | static struct file_system_type ceph_fs_type = { |
| @@ -1062,36 +870,20 @@ static struct file_system_type ceph_fs_type = { | |||
| 1062 | 870 | ||
| 1063 | static int __init init_ceph(void) | 871 | static int __init init_ceph(void) |
| 1064 | { | 872 | { |
| 1065 | int ret = 0; | 873 | int ret = init_caches(); |
| 1066 | |||
| 1067 | ret = ceph_debugfs_init(); | ||
| 1068 | if (ret < 0) | ||
| 1069 | goto out; | ||
| 1070 | |||
| 1071 | ret = ceph_msgr_init(); | ||
| 1072 | if (ret < 0) | ||
| 1073 | goto out_debugfs; | ||
| 1074 | |||
| 1075 | ret = init_caches(); | ||
| 1076 | if (ret) | 874 | if (ret) |
| 1077 | goto out_msgr; | 875 | goto out; |
| 1078 | 876 | ||
| 1079 | ret = register_filesystem(&ceph_fs_type); | 877 | ret = register_filesystem(&ceph_fs_type); |
| 1080 | if (ret) | 878 | if (ret) |
| 1081 | goto out_icache; | 879 | goto out_icache; |
| 1082 | 880 | ||
| 1083 | pr_info("loaded (mon/mds/osd proto %d/%d/%d, osdmap %d/%d %d/%d)\n", | 881 | pr_info("loaded (mds proto %d)\n", CEPH_MDSC_PROTOCOL); |
| 1084 | CEPH_MONC_PROTOCOL, CEPH_MDSC_PROTOCOL, CEPH_OSDC_PROTOCOL, | 882 | |
| 1085 | CEPH_OSDMAP_VERSION, CEPH_OSDMAP_VERSION_EXT, | ||
| 1086 | CEPH_OSDMAP_INC_VERSION, CEPH_OSDMAP_INC_VERSION_EXT); | ||
| 1087 | return 0; | 883 | return 0; |
| 1088 | 884 | ||
| 1089 | out_icache: | 885 | out_icache: |
| 1090 | destroy_caches(); | 886 | destroy_caches(); |
| 1091 | out_msgr: | ||
| 1092 | ceph_msgr_exit(); | ||
| 1093 | out_debugfs: | ||
| 1094 | ceph_debugfs_cleanup(); | ||
| 1095 | out: | 887 | out: |
| 1096 | return ret; | 888 | return ret; |
| 1097 | } | 889 | } |
| @@ -1101,8 +893,6 @@ static void __exit exit_ceph(void) | |||
| 1101 | dout("exit_ceph\n"); | 893 | dout("exit_ceph\n"); |
| 1102 | unregister_filesystem(&ceph_fs_type); | 894 | unregister_filesystem(&ceph_fs_type); |
| 1103 | destroy_caches(); | 895 | destroy_caches(); |
| 1104 | ceph_msgr_exit(); | ||
| 1105 | ceph_debugfs_cleanup(); | ||
| 1106 | } | 896 | } |
| 1107 | 897 | ||
| 1108 | module_init(init_ceph); | 898 | module_init(init_ceph); |
