1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * linux/fs/lockd/svcsubs.c 4 * 5 * Various support routines for the NLM server. 6 * 7 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> 8 */ 9 10 #include <linux/types.h> 11 #include <linux/string.h> 12 #include <linux/time.h> 13 #include <linux/in.h> 14 #include <linux/slab.h> 15 #include <linux/mutex.h> 16 #include <linux/sunrpc/svc.h> 17 #include <linux/sunrpc/addr.h> 18 #include <linux/module.h> 19 #include <linux/mount.h> 20 21 #include "lockd.h" 22 #include "share.h" 23 24 #define NLMDBG_FACILITY NLMDBG_SVCSUBS 25 26 27 /* 28 * Global file hash table 29 */ 30 #define FILE_HASH_BITS 7 31 #define FILE_NRHASH (1<<FILE_HASH_BITS) 32 static struct hlist_head nlm_files[FILE_NRHASH]; 33 static DEFINE_MUTEX(nlm_file_mutex); 34 35 #ifdef CONFIG_SUNRPC_DEBUG 36 static inline void nlm_debug_print_fh(char *msg, struct nfs_fh *f) 37 { 38 u32 *fhp = (u32*)f->data; 39 40 /* print the first 32 bytes of the fh */ 41 dprintk("lockd: %s (%08x %08x %08x %08x %08x %08x %08x %08x)\n", 42 msg, fhp[0], fhp[1], fhp[2], fhp[3], 43 fhp[4], fhp[5], fhp[6], fhp[7]); 44 } 45 46 static inline void nlm_debug_print_file(char *msg, struct nlm_file *file) 47 { 48 struct inode *inode = nlmsvc_file_inode(file); 49 50 dprintk("lockd: %s %s/%llu\n", 51 msg, inode->i_sb->s_id, inode->i_ino); 52 } 53 #else 54 static inline void nlm_debug_print_fh(char *msg, struct nfs_fh *f) 55 { 56 return; 57 } 58 59 static inline void nlm_debug_print_file(char *msg, struct nlm_file *file) 60 { 61 return; 62 } 63 #endif 64 65 static inline unsigned int file_hash(struct nfs_fh *f) 66 { 67 unsigned int tmp=0; 68 int i; 69 for (i = 0; i < LOCKD_FH_HASH_SIZE; i++) 70 tmp += f->data[i]; 71 return tmp & (FILE_NRHASH - 1); 72 } 73 74 int lock_to_openmode(struct file_lock *lock) 75 { 76 return lock_is_write(lock) ? O_WRONLY : O_RDONLY; 77 } 78 79 /* 80 * Open the file. Note that if we're reexporting, for example, 81 * this could block the lockd thread for a while. 82 * 83 * We have to make sure we have the right credential to open 84 * the file. 85 * 86 * @mode is O_RDONLY, O_WRONLY, or O_RDWR. O_RDWR means success 87 * is achieved with EITHER O_RDONLY or O_WRONLY; it does not 88 * require both. 89 */ 90 static __be32 nlm_do_fopen(struct svc_rqst *rqstp, 91 struct nlm_file *file, int mode) 92 { 93 __be32 nlmerr = nlm__int__failed; 94 __be32 deferred = 0; 95 int error; 96 int m; 97 98 for (m = O_RDONLY; m <= O_WRONLY; m++) { 99 struct file **fp = &file->f_file[m]; 100 101 if (mode != O_RDWR && mode != m) 102 continue; 103 if (*fp) 104 return nlm_granted; 105 106 error = nlmsvc_ops->fopen(rqstp, &file->f_handle, fp, m); 107 if (!error) 108 return nlm_granted; 109 110 dprintk("lockd: open failed (errno %d)\n", error); 111 switch (error) { 112 case -EWOULDBLOCK: 113 nlmerr = nlm__int__drop_reply; 114 deferred = nlmerr; 115 break; 116 case -ESTALE: 117 nlmerr = nlm__int__stale_fh; 118 break; 119 default: 120 nlmerr = nlm__int__failed; 121 break; 122 } 123 } 124 125 return deferred ? deferred : nlmerr; 126 } 127 128 /* 129 * Lookup file info. If it doesn't exist, create a file info struct 130 * and open a (VFS) file for the given inode. 131 */ 132 __be32 133 nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, 134 struct lockd_lock *lock, int mode) 135 { 136 struct nlm_file *file; 137 unsigned int hash; 138 __be32 nfserr; 139 140 nlm_debug_print_fh("nlm_lookup_file", &lock->fh); 141 142 hash = file_hash(&lock->fh); 143 144 /* Lock file table */ 145 mutex_lock(&nlm_file_mutex); 146 147 hlist_for_each_entry(file, &nlm_files[hash], f_list) 148 if (!nfs_compare_fh(&file->f_handle, &lock->fh)) { 149 mutex_lock(&file->f_mutex); 150 nfserr = nlm_do_fopen(rqstp, file, mode); 151 mutex_unlock(&file->f_mutex); 152 if (nfserr) 153 goto out_unlock; 154 goto found; 155 } 156 nlm_debug_print_fh("creating file for", &lock->fh); 157 158 nfserr = nlm_lck_denied_nolocks; 159 file = kzalloc_obj(*file); 160 if (!file) 161 goto out_free; 162 163 memcpy(&file->f_handle, &lock->fh, sizeof(struct nfs_fh)); 164 mutex_init(&file->f_mutex); 165 INIT_HLIST_NODE(&file->f_list); 166 INIT_LIST_HEAD(&file->f_blocks); 167 168 nfserr = nlm_do_fopen(rqstp, file, mode); 169 if (nfserr) 170 goto out_free; 171 172 hlist_add_head(&file->f_list, &nlm_files[hash]); 173 174 found: 175 dprintk("lockd: found file %p (count %d)\n", file, file->f_count); 176 *result = file; 177 file->f_count++; 178 179 out_unlock: 180 mutex_unlock(&nlm_file_mutex); 181 return nfserr; 182 183 out_free: 184 kfree(file); 185 goto out_unlock; 186 } 187 188 /* 189 * Delete a file after having released all locks, blocks and shares 190 */ 191 static inline void 192 nlm_delete_file(struct nlm_file *file) 193 { 194 nlm_debug_print_file("closing file", file); 195 if (!hlist_unhashed(&file->f_list)) { 196 hlist_del(&file->f_list); 197 if (file->f_file[O_RDONLY]) 198 nlmsvc_ops->fclose(file->f_file[O_RDONLY]); 199 if (file->f_file[O_WRONLY]) 200 nlmsvc_ops->fclose(file->f_file[O_WRONLY]); 201 kfree(file); 202 } else { 203 printk(KERN_WARNING "lockd: attempt to release unknown file!\n"); 204 } 205 } 206 207 static int nlm_unlock_files(struct nlm_file *file, const struct file_lock *fl) 208 { 209 struct file_lock lock; 210 211 locks_init_lock(&lock); 212 lock.c.flc_type = F_UNLCK; 213 lock.fl_start = 0; 214 lock.fl_end = OFFSET_MAX; 215 lock.c.flc_owner = fl->c.flc_owner; 216 lock.c.flc_pid = fl->c.flc_pid; 217 lock.c.flc_flags = FL_POSIX; 218 219 lock.c.flc_file = file->f_file[O_RDONLY]; 220 if (lock.c.flc_file && vfs_lock_file(lock.c.flc_file, F_SETLK, &lock, NULL)) 221 goto out_err; 222 lock.c.flc_file = file->f_file[O_WRONLY]; 223 if (lock.c.flc_file && vfs_lock_file(lock.c.flc_file, F_SETLK, &lock, NULL)) 224 goto out_err; 225 return 0; 226 out_err: 227 pr_warn("lockd: unlock failure in %s:%d\n", __FILE__, __LINE__); 228 return 1; 229 } 230 231 /* 232 * Loop over all locks on the given file and perform the specified 233 * action. 234 */ 235 static int 236 nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, 237 nlm_host_match_fn_t match) 238 { 239 struct inode *inode = nlmsvc_file_inode(file); 240 struct file_lock *fl; 241 struct file_lock_context *flctx = locks_inode_context(inode); 242 struct nlm_host *lockhost; 243 244 if (!flctx || list_empty_careful(&flctx->flc_posix)) 245 return 0; 246 again: 247 file->f_locks = 0; 248 spin_lock(&flctx->flc_lock); 249 for_each_file_lock(fl, &flctx->flc_posix) { 250 if (fl->fl_lmops != &nlmsvc_lock_operations) 251 continue; 252 253 /* update current lock count */ 254 file->f_locks++; 255 256 lockhost = ((struct nlm_lockowner *) fl->c.flc_owner)->host; 257 if (match(lockhost, host)) { 258 259 spin_unlock(&flctx->flc_lock); 260 if (nlm_unlock_files(file, fl)) 261 return 1; 262 goto again; 263 } 264 } 265 spin_unlock(&flctx->flc_lock); 266 267 return 0; 268 } 269 270 static int 271 nlmsvc_always_match(void *dummy1, struct nlm_host *dummy2) 272 { 273 return 1; 274 } 275 276 /* 277 * Inspect a single file 278 */ 279 static inline int 280 nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, nlm_host_match_fn_t match) 281 { 282 nlmsvc_traverse_blocks(host, file, match); 283 nlmsvc_traverse_shares(host, file, match); 284 return nlm_traverse_locks(host, file, match); 285 } 286 287 /* 288 * Quick check whether there are still any locks, blocks or 289 * shares on a given file. 290 */ 291 static inline int 292 nlm_file_inuse(struct nlm_file *file) 293 { 294 struct inode *inode = nlmsvc_file_inode(file); 295 struct file_lock *fl; 296 struct file_lock_context *flctx = locks_inode_context(inode); 297 298 if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares) 299 return 1; 300 301 if (flctx && !list_empty_careful(&flctx->flc_posix)) { 302 spin_lock(&flctx->flc_lock); 303 for_each_file_lock(fl, &flctx->flc_posix) { 304 if (fl->fl_lmops == &nlmsvc_lock_operations) { 305 spin_unlock(&flctx->flc_lock); 306 return 1; 307 } 308 } 309 spin_unlock(&flctx->flc_lock); 310 } 311 file->f_locks = 0; 312 return 0; 313 } 314 315 static void nlm_close_files(struct nlm_file *file) 316 { 317 if (file->f_file[O_RDONLY]) 318 nlmsvc_ops->fclose(file->f_file[O_RDONLY]); 319 if (file->f_file[O_WRONLY]) 320 nlmsvc_ops->fclose(file->f_file[O_WRONLY]); 321 } 322 323 /* 324 * Loop over all files in the file table. 325 */ 326 static int 327 nlm_traverse_files(void *data, nlm_host_match_fn_t match, 328 int (*is_failover_file)(void *data, struct nlm_file *file)) 329 { 330 struct hlist_node *next; 331 struct nlm_file *file; 332 int i, ret = 0; 333 334 mutex_lock(&nlm_file_mutex); 335 for (i = 0; i < FILE_NRHASH; i++) { 336 hlist_for_each_entry_safe(file, next, &nlm_files[i], f_list) { 337 if (is_failover_file && !is_failover_file(data, file)) 338 continue; 339 file->f_count++; 340 mutex_unlock(&nlm_file_mutex); 341 342 /* Traverse locks, blocks and shares of this file 343 * and update file->f_locks count */ 344 if (nlm_inspect_file(data, file, match)) 345 ret = 1; 346 347 mutex_lock(&nlm_file_mutex); 348 file->f_count--; 349 /* No more references to this file. Let go of it. */ 350 if (list_empty(&file->f_blocks) && !file->f_locks 351 && !file->f_shares && !file->f_count) { 352 hlist_del(&file->f_list); 353 nlm_close_files(file); 354 kfree(file); 355 } 356 } 357 } 358 mutex_unlock(&nlm_file_mutex); 359 return ret; 360 } 361 362 /* 363 * Release file. If there are no more remote locks on this file, 364 * close it and free the handle. 365 * 366 * Note that we can't do proper reference counting without major 367 * contortions because the code in fs/locks.c creates, deletes and 368 * splits locks without notification. Our only way is to walk the 369 * entire lock list each time we remove a lock. 370 */ 371 void 372 nlm_release_file(struct nlm_file *file) 373 { 374 dprintk("lockd: nlm_release_file(%p, ct = %d)\n", 375 file, file->f_count); 376 377 /* Lock file table */ 378 mutex_lock(&nlm_file_mutex); 379 380 /* If there are no more locks etc, delete the file */ 381 if (--file->f_count == 0 && !nlm_file_inuse(file)) 382 nlm_delete_file(file); 383 384 mutex_unlock(&nlm_file_mutex); 385 } 386 387 /* 388 * Helpers function for resource traversal 389 * 390 * nlmsvc_mark_host: 391 * used by the garbage collector; simply sets h_inuse only for those 392 * hosts, which passed network check. 393 * Always returns 0. 394 * 395 * nlmsvc_same_host: 396 * returns 1 iff the two hosts match. Used to release 397 * all resources bound to a specific host. 398 * 399 * nlmsvc_is_client: 400 * returns 1 iff the host is a client. 401 * Used by nlmsvc_invalidate_all 402 */ 403 404 static int 405 nlmsvc_mark_host(void *data, struct nlm_host *hint) 406 { 407 struct nlm_host *host = data; 408 409 if ((hint->net == NULL) || 410 (host->net == hint->net)) 411 host->h_inuse = 1; 412 return 0; 413 } 414 415 static int 416 nlmsvc_same_host(void *data, struct nlm_host *other) 417 { 418 struct nlm_host *host = data; 419 420 return host == other; 421 } 422 423 static int 424 nlmsvc_is_client(void *data, struct nlm_host *dummy) 425 { 426 struct nlm_host *host = data; 427 428 if (host->h_server) { 429 /* we are destroying locks even though the client 430 * hasn't asked us too, so don't unmonitor the 431 * client 432 */ 433 if (host->h_nsmhandle) 434 host->h_nsmhandle->sm_sticky = 1; 435 return 1; 436 } else 437 return 0; 438 } 439 440 /* 441 * Mark all hosts that still hold resources 442 */ 443 void 444 nlmsvc_mark_resources(struct net *net) 445 { 446 struct nlm_host hint; 447 448 dprintk("lockd: %s for net %x\n", __func__, net ? net->ns.inum : 0); 449 hint.net = net; 450 nlm_traverse_files(&hint, nlmsvc_mark_host, NULL); 451 } 452 453 /* 454 * Release all resources held by the given client 455 */ 456 void 457 nlmsvc_free_host_resources(struct nlm_host *host) 458 { 459 dprintk("lockd: nlmsvc_free_host_resources\n"); 460 461 if (nlm_traverse_files(host, nlmsvc_same_host, NULL)) { 462 printk(KERN_WARNING 463 "lockd: couldn't remove all locks held by %s\n", 464 host->h_name); 465 BUG(); 466 } 467 } 468 469 /** 470 * nlmsvc_invalidate_all - remove all locks held for clients 471 * 472 * Release all locks held by NFS clients. 473 * 474 */ 475 void 476 nlmsvc_invalidate_all(void) 477 { 478 /* 479 * Previously, the code would call 480 * nlmsvc_free_host_resources for each client in 481 * turn, which is about as inefficient as it gets. 482 * Now we just do it once in nlm_traverse_files. 483 */ 484 nlm_traverse_files(NULL, nlmsvc_is_client, NULL); 485 } 486 487 488 static int 489 nlmsvc_match_sb(void *datap, struct nlm_file *file) 490 { 491 struct super_block *sb = datap; 492 493 return sb == nlmsvc_file_inode(file)->i_sb; 494 } 495 496 /** 497 * nlmsvc_unlock_all_by_sb - release locks held on this file system 498 * @sb: super block 499 * 500 * Release all locks held by clients accessing this file system. 501 */ 502 int 503 nlmsvc_unlock_all_by_sb(struct super_block *sb) 504 { 505 int ret; 506 507 ret = nlm_traverse_files(sb, nlmsvc_always_match, nlmsvc_match_sb); 508 return ret ? -EIO : 0; 509 } 510 EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_sb); 511 512 static int 513 nlmsvc_match_ip(void *datap, struct nlm_host *host) 514 { 515 return rpc_cmp_addr(nlm_srcaddr(host), datap); 516 } 517 518 /** 519 * nlmsvc_unlock_all_by_ip - release local locks by IP address 520 * @server_addr: server's IP address as seen by clients 521 * 522 * Release all locks held by clients accessing this host 523 * via the passed in IP address. 524 */ 525 int 526 nlmsvc_unlock_all_by_ip(struct sockaddr *server_addr) 527 { 528 int ret; 529 530 ret = nlm_traverse_files(server_addr, nlmsvc_match_ip, NULL); 531 return ret ? -EIO : 0; 532 } 533 EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_ip); 534