1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2012 Bryan Schumaker <bjschuma@netapp.com> 4 */ 5 #include <linux/init.h> 6 #include <linux/module.h> 7 #include <linux/mount.h> 8 #include <linux/nfs4_mount.h> 9 #include <linux/nfs_fs.h> 10 #include "delegation.h" 11 #include "internal.h" 12 #include "nfs4_fs.h" 13 #include "nfs4idmap.h" 14 #include "dns_resolve.h" 15 #include "pnfs.h" 16 #include "nfs.h" 17 18 #define NFSDBG_FACILITY NFSDBG_VFS 19 20 static int nfs4_write_inode(struct inode *inode, struct writeback_control *wbc); 21 static void nfs4_evict_inode(struct inode *inode); 22 23 static const struct super_operations nfs4_sops = { 24 .alloc_inode = nfs_alloc_inode, 25 .free_inode = nfs_free_inode, 26 .write_inode = nfs4_write_inode, 27 .drop_inode = nfs_drop_inode, 28 .statfs = nfs_statfs, 29 .evict_inode = nfs4_evict_inode, 30 .umount_begin = nfs_umount_begin, 31 .show_options = nfs_show_options, 32 .show_devname = nfs_show_devname, 33 .show_path = nfs_show_path, 34 .show_stats = nfs_show_stats, 35 }; 36 37 struct nfs_subversion nfs_v4 = { 38 .owner = THIS_MODULE, 39 .nfs_fs = &nfs4_fs_type, 40 .rpc_vers = &nfs_version4, 41 .rpc_ops = &nfs_v4_clientops, 42 .sops = &nfs4_sops, 43 .xattr = nfs4_xattr_handlers, 44 }; 45 46 static int nfs4_write_inode(struct inode *inode, struct writeback_control *wbc) 47 { 48 int ret = nfs_write_inode(inode, wbc); 49 50 if (ret == 0) 51 ret = pnfs_layoutcommit_inode(inode, 52 wbc->sync_mode == WB_SYNC_ALL); 53 return ret; 54 } 55 56 /* 57 * Clean out any remaining NFSv4 state that might be left over due 58 * to open() calls that passed nfs_atomic_lookup, but failed to call 59 * nfs_open(). 60 */ 61 static void nfs4_evict_inode(struct inode *inode) 62 { 63 truncate_inode_pages_final(&inode->i_data); 64 clear_inode(inode); 65 /* If we are holding a delegation, return and free it */ 66 nfs_inode_evict_delegation(inode); 67 /* Note that above delegreturn would trigger pnfs return-on-close */ 68 pnfs_return_layout(inode); 69 pnfs_destroy_layout(NFS_I(inode)); 70 /* First call standard NFS clear_inode() code */ 71 nfs_clear_inode(inode); 72 } 73 74 struct nfs_referral_count { 75 struct list_head list; 76 const struct task_struct *task; 77 unsigned int referral_count; 78 }; 79 80 static LIST_HEAD(nfs_referral_count_list); 81 static DEFINE_SPINLOCK(nfs_referral_count_list_lock); 82 83 static struct nfs_referral_count *nfs_find_referral_count(void) 84 { 85 struct nfs_referral_count *p; 86 87 list_for_each_entry(p, &nfs_referral_count_list, list) { 88 if (p->task == current) 89 return p; 90 } 91 return NULL; 92 } 93 94 #define NFS_MAX_NESTED_REFERRALS 2 95 96 static int nfs_referral_loop_protect(void) 97 { 98 struct nfs_referral_count *p, *new; 99 int ret = -ENOMEM; 100 101 new = kmalloc(sizeof(*new), GFP_KERNEL); 102 if (!new) 103 goto out; 104 new->task = current; 105 new->referral_count = 1; 106 107 ret = 0; 108 spin_lock(&nfs_referral_count_list_lock); 109 p = nfs_find_referral_count(); 110 if (p != NULL) { 111 if (p->referral_count >= NFS_MAX_NESTED_REFERRALS) 112 ret = -ELOOP; 113 else 114 p->referral_count++; 115 } else { 116 list_add(&new->list, &nfs_referral_count_list); 117 new = NULL; 118 } 119 spin_unlock(&nfs_referral_count_list_lock); 120 kfree(new); 121 out: 122 return ret; 123 } 124 125 static void nfs_referral_loop_unprotect(void) 126 { 127 struct nfs_referral_count *p; 128 129 spin_lock(&nfs_referral_count_list_lock); 130 p = nfs_find_referral_count(); 131 p->referral_count--; 132 if (p->referral_count == 0) 133 list_del(&p->list); 134 else 135 p = NULL; 136 spin_unlock(&nfs_referral_count_list_lock); 137 kfree(p); 138 } 139 140 static int do_nfs4_mount(struct nfs_server *server, 141 struct fs_context *fc, 142 const char *hostname, 143 const char *export_path) 144 { 145 struct nfs_fs_context *root_ctx; 146 struct fs_context *root_fc; 147 struct vfsmount *root_mnt; 148 struct dentry *dentry; 149 size_t len; 150 int ret; 151 152 struct fs_parameter param = { 153 .key = "source", 154 .type = fs_value_is_string, 155 .dirfd = -1, 156 }; 157 158 if (IS_ERR(server)) 159 return PTR_ERR(server); 160 161 root_fc = vfs_dup_fs_context(fc); 162 if (IS_ERR(root_fc)) { 163 nfs_free_server(server); 164 return PTR_ERR(root_fc); 165 } 166 kfree(root_fc->source); 167 root_fc->source = NULL; 168 169 root_ctx = nfs_fc2context(root_fc); 170 root_ctx->internal = true; 171 root_ctx->server = server; 172 /* We leave export_path unset as it's not used to find the root. */ 173 174 len = strlen(hostname) + 5; 175 param.string = kmalloc(len, GFP_KERNEL); 176 if (param.string == NULL) { 177 put_fs_context(root_fc); 178 return -ENOMEM; 179 } 180 181 /* Does hostname needs to be enclosed in brackets? */ 182 if (strchr(hostname, ':')) 183 param.size = snprintf(param.string, len, "[%s]:/", hostname); 184 else 185 param.size = snprintf(param.string, len, "%s:/", hostname); 186 ret = vfs_parse_fs_param(root_fc, ¶m); 187 kfree(param.string); 188 if (ret < 0) { 189 put_fs_context(root_fc); 190 return ret; 191 } 192 root_mnt = fc_mount(root_fc); 193 put_fs_context(root_fc); 194 195 if (IS_ERR(root_mnt)) 196 return PTR_ERR(root_mnt); 197 198 ret = nfs_referral_loop_protect(); 199 if (ret) { 200 mntput(root_mnt); 201 return ret; 202 } 203 204 dentry = mount_subtree(root_mnt, export_path); 205 nfs_referral_loop_unprotect(); 206 207 if (IS_ERR(dentry)) 208 return PTR_ERR(dentry); 209 210 fc->root = dentry; 211 return 0; 212 } 213 214 int nfs4_try_get_tree(struct fs_context *fc) 215 { 216 struct nfs_fs_context *ctx = nfs_fc2context(fc); 217 int err; 218 219 dfprintk(MOUNT, "--> nfs4_try_get_tree()\n"); 220 221 /* We create a mount for the server's root, walk to the requested 222 * location and then create another mount for that. 223 */ 224 err= do_nfs4_mount(nfs4_create_server(fc), 225 fc, ctx->nfs_server.hostname, 226 ctx->nfs_server.export_path); 227 if (err) { 228 nfs_errorf(fc, "NFS4: Couldn't follow remote path"); 229 dfprintk(MOUNT, "<-- nfs4_try_get_tree() = %d [error]\n", err); 230 } else { 231 dfprintk(MOUNT, "<-- nfs4_try_get_tree() = 0\n"); 232 } 233 return err; 234 } 235 236 /* 237 * Create an NFS4 server record on referral traversal 238 */ 239 int nfs4_get_referral_tree(struct fs_context *fc) 240 { 241 struct nfs_fs_context *ctx = nfs_fc2context(fc); 242 int err; 243 244 dprintk("--> nfs4_referral_mount()\n"); 245 246 /* create a new volume representation */ 247 err = do_nfs4_mount(nfs4_create_referral_server(fc), 248 fc, ctx->nfs_server.hostname, 249 ctx->nfs_server.export_path); 250 if (err) { 251 nfs_errorf(fc, "NFS4: Couldn't follow remote path"); 252 dfprintk(MOUNT, "<-- nfs4_get_referral_tree() = %d [error]\n", err); 253 } else { 254 dfprintk(MOUNT, "<-- nfs4_get_referral_tree() = 0\n"); 255 } 256 return err; 257 } 258 259 static int __init init_nfs_v4(void) 260 { 261 int err; 262 263 err = nfs_dns_resolver_init(); 264 if (err) 265 goto out; 266 267 err = nfs_idmap_init(); 268 if (err) 269 goto out1; 270 271 err = nfs4_register_sysctl(); 272 if (err) 273 goto out2; 274 275 register_nfs_version(&nfs_v4); 276 return 0; 277 out2: 278 nfs_idmap_quit(); 279 out1: 280 nfs_dns_resolver_destroy(); 281 out: 282 return err; 283 } 284 285 static void __exit exit_nfs_v4(void) 286 { 287 /* Not called in the _init(), conditionally loaded */ 288 nfs4_pnfs_v3_ds_connect_unload(); 289 290 unregister_nfs_version(&nfs_v4); 291 nfs4_unregister_sysctl(); 292 nfs_idmap_quit(); 293 nfs_dns_resolver_destroy(); 294 } 295 296 MODULE_LICENSE("GPL"); 297 298 module_init(init_nfs_v4); 299 module_exit(exit_nfs_v4); 300