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

Keep read and write fds with each nlm_file

We shouldn't really be using a read-only file descriptor to take a write
lock.

Most filesystems will put up with it. But NFS, for example, won't.

Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>

authored by

J. Bruce Fields and committed by
Chuck Lever
7f024fcd b661601a

+111 -44
+3 -1
fs/lockd/svc4proc.c
··· 40 40 41 41 /* Obtain file pointer. Not used by FREE_ALL call. */ 42 42 if (filp != NULL) { 43 + int mode = lock_to_openmode(&lock->fl); 44 + 43 45 error = nlm_lookup_file(rqstp, &file, lock); 44 46 if (error) 45 47 goto no_locks; 46 48 *filp = file; 47 49 48 50 /* Set up the missing parts of the file_lock structure */ 49 - lock->fl.fl_file = file->f_file; 51 + lock->fl.fl_file = file->f_file[mode]; 50 52 lock->fl.fl_pid = current->tgid; 51 53 lock->fl.fl_lmops = &nlmsvc_lock_operations; 52 54 nlmsvc_locks_init_private(&lock->fl, host, (pid_t)lock->svid);
+19 -6
fs/lockd/svclock.c
··· 471 471 { 472 472 struct nlm_block *block = NULL; 473 473 int error; 474 + int mode; 474 475 __be32 ret; 475 476 476 477 dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n", ··· 525 524 526 525 if (!wait) 527 526 lock->fl.fl_flags &= ~FL_SLEEP; 528 - error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL); 527 + mode = lock_to_openmode(&lock->fl); 528 + error = vfs_lock_file(file->f_file[mode], F_SETLK, &lock->fl, NULL); 529 529 lock->fl.fl_flags &= ~FL_SLEEP; 530 530 531 531 dprintk("lockd: vfs_lock_file returned %d\n", error); ··· 579 577 struct nlm_lock *conflock, struct nlm_cookie *cookie) 580 578 { 581 579 int error; 580 + int mode; 582 581 __be32 ret; 583 582 struct nlm_lockowner *test_owner; 584 583 ··· 598 595 /* If there's a conflicting lock, remember to clean up the test lock */ 599 596 test_owner = (struct nlm_lockowner *)lock->fl.fl_owner; 600 597 601 - error = vfs_test_lock(file->f_file, &lock->fl); 598 + mode = lock_to_openmode(&lock->fl); 599 + error = vfs_test_lock(file->f_file[mode], &lock->fl); 602 600 if (error) { 603 601 /* We can't currently deal with deferred test requests */ 604 602 if (error == FILE_LOCK_DEFERRED) ··· 645 641 __be32 646 642 nlmsvc_unlock(struct net *net, struct nlm_file *file, struct nlm_lock *lock) 647 643 { 648 - int error; 644 + int error = 0; 649 645 650 646 dprintk("lockd: nlmsvc_unlock(%s/%ld, pi=%d, %Ld-%Ld)\n", 651 647 nlmsvc_file_inode(file)->i_sb->s_id, ··· 658 654 nlmsvc_cancel_blocked(net, file, lock); 659 655 660 656 lock->fl.fl_type = F_UNLCK; 661 - error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL); 657 + if (file->f_file[O_RDONLY]) 658 + error = vfs_lock_file(file->f_file[O_RDONLY], F_SETLK, 659 + &lock->fl, NULL); 660 + if (file->f_file[O_WRONLY]) 661 + error = vfs_lock_file(file->f_file[O_WRONLY], F_SETLK, 662 + &lock->fl, NULL); 662 663 663 664 return (error < 0)? nlm_lck_denied_nolocks : nlm_granted; 664 665 } ··· 680 671 { 681 672 struct nlm_block *block; 682 673 int status = 0; 674 + int mode; 683 675 684 676 dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n", 685 677 nlmsvc_file_inode(file)->i_sb->s_id, ··· 696 686 block = nlmsvc_lookup_block(file, lock); 697 687 mutex_unlock(&file->f_mutex); 698 688 if (block != NULL) { 699 - vfs_cancel_lock(block->b_file->f_file, 689 + mode = lock_to_openmode(&lock->fl); 690 + vfs_cancel_lock(block->b_file->f_file[mode], 700 691 &block->b_call->a_args.lock.fl); 701 692 status = nlmsvc_unlink_block(block); 702 693 nlmsvc_release_block(block); ··· 814 803 { 815 804 struct nlm_file *file = block->b_file; 816 805 struct nlm_lock *lock = &block->b_call->a_args.lock; 806 + int mode; 817 807 int error; 818 808 loff_t fl_start, fl_end; 819 809 ··· 840 828 lock->fl.fl_flags |= FL_SLEEP; 841 829 fl_start = lock->fl.fl_start; 842 830 fl_end = lock->fl.fl_end; 843 - error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL); 831 + mode = lock_to_openmode(&lock->fl); 832 + error = vfs_lock_file(file->f_file[mode], F_SETLK, &lock->fl, NULL); 844 833 lock->fl.fl_flags &= ~FL_SLEEP; 845 834 lock->fl.fl_start = fl_start; 846 835 lock->fl.fl_end = fl_end;
+3 -1
fs/lockd/svcproc.c
··· 55 55 struct nlm_host *host = NULL; 56 56 struct nlm_file *file = NULL; 57 57 struct nlm_lock *lock = &argp->lock; 58 + int mode; 58 59 __be32 error = 0; 59 60 60 61 /* nfsd callbacks must have been installed for this procedure */ ··· 76 75 *filp = file; 77 76 78 77 /* Set up the missing parts of the file_lock structure */ 79 - lock->fl.fl_file = file->f_file; 78 + mode = lock_to_openmode(&lock->fl); 79 + lock->fl.fl_file = file->f_file[mode]; 80 80 lock->fl.fl_pid = current->tgid; 81 81 lock->fl.fl_lmops = &nlmsvc_lock_operations; 82 82 nlmsvc_locks_init_private(&lock->fl, host, (pid_t)lock->svid);
+71 -31
fs/lockd/svcsubs.c
··· 71 71 return tmp & (FILE_NRHASH - 1); 72 72 } 73 73 74 + int lock_to_openmode(struct file_lock *lock) 75 + { 76 + return (lock->fl_type == F_WRLCK) ? 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 + static __be32 nlm_do_fopen(struct svc_rqst *rqstp, 87 + struct nlm_file *file, int mode) 88 + { 89 + struct file **fp = &file->f_file[mode]; 90 + __be32 nfserr; 91 + 92 + if (*fp) 93 + return 0; 94 + nfserr = nlmsvc_ops->fopen(rqstp, &file->f_handle, fp, mode); 95 + if (nfserr) 96 + dprintk("lockd: open failed (error %d)\n", nfserr); 97 + return nfserr; 98 + } 99 + 74 100 /* 75 101 * Lookup file info. If it doesn't exist, create a file info struct 76 102 * and open a (VFS) file for the given inode. 77 - * 78 - * FIXME: 79 - * Note that we open the file O_RDONLY even when creating write locks. 80 - * This is not quite right, but for now, we assume the client performs 81 - * the proper R/W checking. 82 103 */ 83 104 __be32 84 105 nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, ··· 108 87 struct nlm_file *file; 109 88 unsigned int hash; 110 89 __be32 nfserr; 90 + int mode; 111 91 112 92 nlm_debug_print_fh("nlm_lookup_file", &lock->fh); 113 93 114 94 hash = file_hash(&lock->fh); 95 + mode = lock_to_openmode(&lock->fl); 115 96 116 97 /* Lock file table */ 117 98 mutex_lock(&nlm_file_mutex); 118 99 119 100 hlist_for_each_entry(file, &nlm_files[hash], f_list) 120 - if (!nfs_compare_fh(&file->f_handle, &lock->fh)) 101 + if (!nfs_compare_fh(&file->f_handle, &lock->fh)) { 102 + mutex_lock(&file->f_mutex); 103 + nfserr = nlm_do_fopen(rqstp, file, mode); 104 + mutex_unlock(&file->f_mutex); 121 105 goto found; 122 - 106 + } 123 107 nlm_debug_print_fh("creating file for", &lock->fh); 124 108 125 109 nfserr = nlm_lck_denied_nolocks; 126 110 file = kzalloc(sizeof(*file), GFP_KERNEL); 127 111 if (!file) 128 - goto out_unlock; 112 + goto out_free; 129 113 130 114 memcpy(&file->f_handle, &lock->fh, sizeof(struct nfs_fh)); 131 115 mutex_init(&file->f_mutex); 132 116 INIT_HLIST_NODE(&file->f_list); 133 117 INIT_LIST_HEAD(&file->f_blocks); 134 118 135 - /* 136 - * Open the file. Note that if we're reexporting, for example, 137 - * this could block the lockd thread for a while. 138 - * 139 - * We have to make sure we have the right credential to open 140 - * the file. 141 - */ 142 - nfserr = nlmsvc_ops->fopen(rqstp, &lock->fh, &file->f_file); 143 - if (nfserr) { 144 - dprintk("lockd: open failed (error %d)\n", nfserr); 145 - goto out_free; 146 - } 119 + nfserr = nlm_do_fopen(rqstp, file, mode); 120 + if (nfserr) 121 + goto out_unlock; 147 122 148 123 hlist_add_head(&file->f_list, &nlm_files[hash]); 149 124 ··· 147 130 dprintk("lockd: found file %p (count %d)\n", file, file->f_count); 148 131 *result = file; 149 132 file->f_count++; 150 - nfserr = 0; 151 133 152 134 out_unlock: 153 135 mutex_unlock(&nlm_file_mutex); ··· 166 150 nlm_debug_print_file("closing file", file); 167 151 if (!hlist_unhashed(&file->f_list)) { 168 152 hlist_del(&file->f_list); 169 - nlmsvc_ops->fclose(file->f_file); 153 + if (file->f_file[O_RDONLY]) 154 + nlmsvc_ops->fclose(file->f_file[O_RDONLY]); 155 + if (file->f_file[O_WRONLY]) 156 + nlmsvc_ops->fclose(file->f_file[O_WRONLY]); 170 157 kfree(file); 171 158 } else { 172 159 printk(KERN_WARNING "lockd: attempt to release unknown file!\n"); 173 160 } 161 + } 162 + 163 + static int nlm_unlock_files(struct nlm_file *file) 164 + { 165 + struct file_lock lock; 166 + struct file *f; 167 + 168 + lock.fl_type = F_UNLCK; 169 + lock.fl_start = 0; 170 + lock.fl_end = OFFSET_MAX; 171 + for (f = file->f_file[0]; f <= file->f_file[1]; f++) { 172 + if (f && vfs_lock_file(f, F_SETLK, &lock, NULL) < 0) { 173 + pr_warn("lockd: unlock failure in %s:%d\n", 174 + __FILE__, __LINE__); 175 + return 1; 176 + } 177 + } 178 + return 0; 174 179 } 175 180 176 181 /* ··· 221 184 222 185 lockhost = ((struct nlm_lockowner *)fl->fl_owner)->host; 223 186 if (match(lockhost, host)) { 224 - struct file_lock lock = *fl; 225 187 226 188 spin_unlock(&flctx->flc_lock); 227 - lock.fl_type = F_UNLCK; 228 - lock.fl_start = 0; 229 - lock.fl_end = OFFSET_MAX; 230 - if (vfs_lock_file(file->f_file, F_SETLK, &lock, NULL) < 0) { 231 - printk("lockd: unlock failure in %s:%d\n", 232 - __FILE__, __LINE__); 189 + if (nlm_unlock_files(file)) 233 190 return 1; 234 - } 235 191 goto again; 236 192 } 237 193 } ··· 278 248 return 0; 279 249 } 280 250 251 + static void nlm_close_files(struct nlm_file *file) 252 + { 253 + struct file *f; 254 + 255 + for (f = file->f_file[0]; f <= file->f_file[1]; f++) 256 + if (f) 257 + nlmsvc_ops->fclose(f); 258 + } 259 + 281 260 /* 282 261 * Loop over all files in the file table. 283 262 */ ··· 317 278 if (list_empty(&file->f_blocks) && !file->f_locks 318 279 && !file->f_shares && !file->f_count) { 319 280 hlist_del(&file->f_list); 320 - nlmsvc_ops->fclose(file->f_file); 281 + nlm_close_files(file); 321 282 kfree(file); 322 283 } 323 284 } ··· 450 411 */ 451 412 nlm_traverse_files(NULL, nlmsvc_is_client, NULL); 452 413 } 414 + 453 415 454 416 static int 455 417 nlmsvc_match_sb(void *datap, struct nlm_file *file)
+6 -2
fs/nfsd/lockd.c
··· 25 25 * Note: we hold the dentry use count while the file is open. 26 26 */ 27 27 static __be32 28 - nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp) 28 + nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp, 29 + int mode) 29 30 { 30 31 __be32 nfserr; 32 + int access; 31 33 struct svc_fh fh; 32 34 33 35 /* must initialize before using! but maxsize doesn't matter */ ··· 38 36 memcpy((char*)&fh.fh_handle.fh_base, f->data, f->size); 39 37 fh.fh_export = NULL; 40 38 41 - nfserr = nfsd_open(rqstp, &fh, S_IFREG, NFSD_MAY_LOCK, filp); 39 + access = (mode == O_WRONLY) ? NFSD_MAY_WRITE : NFSD_MAY_READ; 40 + access |= NFSD_MAY_LOCK; 41 + nfserr = nfsd_open(rqstp, &fh, S_IFREG, access, filp); 42 42 fh_put(&fh); 43 43 /* We return nlm error codes as nlm doesn't know 44 44 * about nfsd, but nfsd does know about nlm..
+2 -1
include/linux/lockd/bind.h
··· 27 27 struct nlmsvc_binding { 28 28 __be32 (*fopen)(struct svc_rqst *, 29 29 struct nfs_fh *, 30 - struct file **); 30 + struct file **, 31 + int mode); 31 32 void (*fclose)(struct file *); 32 33 }; 33 34
+7 -2
include/linux/lockd/lockd.h
··· 10 10 #ifndef LINUX_LOCKD_LOCKD_H 11 11 #define LINUX_LOCKD_LOCKD_H 12 12 13 + /* XXX: a lot of this should really be under fs/lockd. */ 14 + 13 15 #include <linux/in.h> 14 16 #include <linux/in6.h> 15 17 #include <net/ipv6.h> ··· 156 154 struct nlm_file { 157 155 struct hlist_node f_list; /* linked list */ 158 156 struct nfs_fh f_handle; /* NFS file handle */ 159 - struct file * f_file; /* VFS file pointer */ 157 + struct file * f_file[2]; /* VFS file pointers, 158 + indexed by O_ flags */ 160 159 struct nlm_share * f_shares; /* DOS shares */ 161 160 struct list_head f_blocks; /* blocked locks */ 162 161 unsigned int f_locks; /* guesstimate # of locks */ ··· 270 267 /* 271 268 * Server-side lock handling 272 269 */ 270 + int lock_to_openmode(struct file_lock *); 273 271 __be32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *, 274 272 struct nlm_host *, struct nlm_lock *, int, 275 273 struct nlm_cookie *, int); ··· 305 301 306 302 static inline struct inode *nlmsvc_file_inode(struct nlm_file *file) 307 303 { 308 - return locks_inode(file->f_file); 304 + return locks_inode(file->f_file[O_RDONLY] ? 305 + file->f_file[O_RDONLY] : file->f_file[O_WRONLY]); 309 306 } 310 307 311 308 static inline int __nlm_privileged_request4(const struct sockaddr *sap)