Signed-off-by: Malahal Naineni <malahal@xxxxxxxxxx> --- fs/nfs/client.c | 4 +++ fs/nfs/nfs4_fs.h | 3 ++ fs/nfs/nfs4proc.c | 36 +++++++++++++++++++++++++++++++ fs/nfs/nfs4xdr.c | 16 +++++++++---- fs/nfs/super.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/nfs_fs_sb.h | 2 + include/linux/nfs_xdr.h | 3 ++ 7 files changed, 110 insertions(+), 5 deletions(-) diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 2045baa..54de25a 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -1096,6 +1096,8 @@ static struct nfs_server *nfs_alloc_server(void) */ void nfs_free_server(struct nfs_server *server) { + int i; + dprintk("--> nfs_free_server()\n"); nfs_server_remove_lists(server); @@ -1113,6 +1115,8 @@ void nfs_free_server(struct nfs_server *server) nfs_free_iostats(server->io_stats); nfs_free_fhandle(server->rootfh); + for (i = 0; i < NFS_MAX_REPLI_SERVERS; i++) + kfree(server->repli_servers[i]); bdi_destroy(&server->backing_dev_info); kfree(server); nfs_release_automount_timer(); diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 4d7d0ae..7ff0177 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -224,6 +224,9 @@ extern int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, boo extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, struct nfs4_fs_locations *fs_locations, struct page *page); +extern int nfs4_get_fs_locations(struct nfs_server *server, + struct nfs4_fs_locations *locations, struct page *page); + extern void nfs4_release_lockowner(const struct nfs4_lock_state *); extern const struct xattr_handler *nfs4_xattr_handlers[]; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 09674cc..775adb3 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -4814,6 +4814,42 @@ int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_se return err; } +int nfs4_get_fs_locations(struct nfs_server *server, + struct nfs4_fs_locations *locations, struct page *page) +{ + u32 bitmask[2] = { + [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS, + }; + struct nfs4_fs_locations_arg args = { + .fh = server->rootfh, + .page = page, + .bitmask = bitmask, + .replication = 1, + }; + struct nfs4_fs_locations_res res = { + .fs_locations = locations, + .replication = 1, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS], + .rpc_argp = &args, + .rpc_resp = &res, + }; + int status; + + dprintk("--> %s: FSID %llx:%llx on \"%s\"\n", __func__, + (unsigned long long)server->fsid.major, + (unsigned long long)server->fsid.minor, + server->nfs_client->cl_hostname); + + nfs_fattr_init(&locations->fattr); + locations->server = server; + locations->nlocations = 0; + status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); + dprintk("<-- %s status=%d\n", __func__, status); + return status; +} + #ifdef CONFIG_NFS_V4_1 /* * Check the exchange flags returned by the server for invalid flags, having diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 95e92e4..b2fff0f 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -2723,8 +2723,12 @@ static void nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, encode_compound_hdr(xdr, req, &hdr); encode_sequence(xdr, &args->seq_args, &hdr); - encode_putfh(xdr, args->dir_fh, &hdr); - encode_lookup(xdr, args->name, &hdr); + if (args->replication) { + encode_putfh(xdr, args->fh, &hdr); + } else { + encode_putfh(xdr, args->dir_fh, &hdr); + encode_lookup(xdr, args->name, &hdr); + } replen = hdr.replen; /* get the attribute into args->page */ encode_fs_locations(xdr, args->bitmask, &hdr); @@ -6576,9 +6580,11 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, status = decode_putfh(xdr); if (status) goto out; - status = decode_lookup(xdr); - if (status) - goto out; + if (!res->replication) { + status = decode_lookup(xdr); + if (status) + goto out; + } xdr_enter_page(xdr, PAGE_SIZE); status = decode_getfattr(xdr, &res->fs_locations->fattr, res->fs_locations->server); diff --git a/fs/nfs/super.c b/fs/nfs/super.c index f2e7d7c..3b20fc4 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -322,6 +322,7 @@ static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data); static void nfs4_kill_super(struct super_block *sb); +static void nfs4_store_repli_locations(struct dentry *dentry); static struct file_system_type nfs4_fs_type = { .owner = THIS_MODULE, @@ -2829,6 +2830,11 @@ static struct dentry *nfs4_try_mount(int flags, const char *dev_name, dfprintk(MOUNT, "<-- nfs4_try_mount() = %ld%s\n", IS_ERR(res) ? PTR_ERR(res) : 0, IS_ERR(res) ? " [error]" : ""); + + /* Add replication locations */ + if (!IS_ERR(root_mnt)) + nfs4_store_repli_locations(res); + return res; } @@ -3087,4 +3093,49 @@ static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, return res; } +static void nfs4_store_repli_locations(struct dentry *dentry) +{ + struct nfs4_fs_locations *locations; + struct nfs_server *server; + struct page *page; + unsigned int i, s, loc, n; + int err; + + page = alloc_page(GFP_KERNEL); + locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL); + if (!page || !locations) + goto free; + + server = NFS_SERVER(dentry->d_inode); + + /* Free old locations */ + for (i = 0; i < NFS_MAX_REPLI_SERVERS; i++) { + kfree(server->repli_servers[i]); + server->repli_servers[i] = NULL; + } + + err = nfs4_get_fs_locations(server, locations, page); + if (err) + goto free; + + for (n = 0, loc = 0; loc < locations->nlocations && + n < NFS_MAX_REPLI_SERVERS; loc++) { + const struct nfs4_fs_location *location = + &locations->locations[loc]; + for (s = 0; s < location->nservers && + n < NFS_MAX_REPLI_SERVERS; s++) { + const struct nfs4_string *buf = &location->servers[s]; + if (buf->len <= 0 || buf->len > PAGE_SIZE) + continue; + server->repli_servers[n++] = kstrndup(buf->data, + buf->len, + GFP_KERNEL); + } + } + +free: + if (page) + __free_page(page); + kfree(locations); +} #endif /* CONFIG_NFS_V4 */ diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 6532d7b..4970c58 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -158,6 +158,8 @@ struct nfs_server { struct list_head delegations; void (*destroy)(struct nfs_server *); struct nfs_fh *rootfh; +#define NFS_MAX_REPLI_SERVERS 2 + char *repli_servers[NFS_MAX_REPLI_SERVERS]; atomic_t active; /* Keep trace of any activity to this server */ diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index a764cef..ca6debd 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -1004,15 +1004,18 @@ struct nfs4_fs_locations { struct nfs4_fs_locations_arg { const struct nfs_fh *dir_fh; + const struct nfs_fh *fh; const struct qstr *name; struct page *page; const u32 *bitmask; struct nfs4_sequence_args seq_args; + unsigned char replication:1; }; struct nfs4_fs_locations_res { struct nfs4_fs_locations *fs_locations; struct nfs4_sequence_res seq_res; + unsigned char replication:1; }; struct nfs4_secinfo_oid { -- 1.7.8.3 -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html