diff options
author | Pavel Shilovsky <pshilovsky@samba.org> | 2012-09-19 09:22:43 -0400 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2012-09-24 22:46:32 -0400 |
commit | f45d34167c67b083b54690e349e77f59062ef0ea (patch) | |
tree | 6be4f2a62e99e348e6cab03a24a1c45889a6722f /fs | |
parent | 1c0bd60b560cdf63a263f8ff3cebe9f99fe7a47c (diff) |
CIFS: Remove spinlock dependence in brlock processing
Now we need to lock/unlock a spinlock while processing brlock ops
on the inode. Move brlocks of a fid to a separate list and attach
all such lists to the inode. This let us not hold a spinlock.
Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cifs/cifsfs.c | 1 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 18 | ||||
-rw-r--r-- | fs/cifs/file.c | 73 |
3 files changed, 53 insertions, 39 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 3a3e2fee0b3e..e958d9438505 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -233,6 +233,7 @@ cifs_alloc_inode(struct super_block *sb) | |||
233 | to zero by the VFS */ | 233 | to zero by the VFS */ |
234 | /* cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME;*/ | 234 | /* cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME;*/ |
235 | INIT_LIST_HEAD(&cifs_inode->openFileList); | 235 | INIT_LIST_HEAD(&cifs_inode->openFileList); |
236 | INIT_LIST_HEAD(&cifs_inode->llist); | ||
236 | return &cifs_inode->vfs_inode; | 237 | return &cifs_inode->vfs_inode; |
237 | } | 238 | } |
238 | 239 | ||
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 004672f9e16c..b2eb577b5f3f 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -890,13 +890,16 @@ struct cifs_fid { | |||
890 | #endif | 890 | #endif |
891 | }; | 891 | }; |
892 | 892 | ||
893 | struct cifs_fid_locks { | ||
894 | struct list_head llist; | ||
895 | struct cifsFileInfo *cfile; /* fid that owns locks */ | ||
896 | struct list_head locks; /* locks held by fid above */ | ||
897 | }; | ||
898 | |||
893 | struct cifsFileInfo { | 899 | struct cifsFileInfo { |
894 | struct list_head tlist; /* pointer to next fid owned by tcon */ | 900 | struct list_head tlist; /* pointer to next fid owned by tcon */ |
895 | struct list_head flist; /* next fid (file instance) for this inode */ | 901 | struct list_head flist; /* next fid (file instance) for this inode */ |
896 | struct list_head llist; /* | 902 | struct cifs_fid_locks *llist; /* brlocks held by this fid */ |
897 | * brlocks held by this fid, protected by | ||
898 | * lock_mutex from cifsInodeInfo structure | ||
899 | */ | ||
900 | unsigned int uid; /* allows finding which FileInfo structure */ | 903 | unsigned int uid; /* allows finding which FileInfo structure */ |
901 | __u32 pid; /* process id who opened file */ | 904 | __u32 pid; /* process id who opened file */ |
902 | struct cifs_fid fid; /* file id from remote */ | 905 | struct cifs_fid fid; /* file id from remote */ |
@@ -988,11 +991,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file); | |||
988 | 991 | ||
989 | struct cifsInodeInfo { | 992 | struct cifsInodeInfo { |
990 | bool can_cache_brlcks; | 993 | bool can_cache_brlcks; |
991 | struct mutex lock_mutex; /* | 994 | struct list_head llist; /* locks helb by this inode */ |
992 | * protect the field above and llist | 995 | struct mutex lock_mutex; /* protect the fields above */ |
993 | * from every cifsFileInfo structure | ||
994 | * from openFileList | ||
995 | */ | ||
996 | /* BB add in lists for dirty pages i.e. write caching info for oplock */ | 996 | /* BB add in lists for dirty pages i.e. write caching info for oplock */ |
997 | struct list_head openFileList; | 997 | struct list_head openFileList; |
998 | __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ | 998 | __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 2421ec28df14..63963730cb28 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -245,11 +245,25 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, | |||
245 | struct inode *inode = dentry->d_inode; | 245 | struct inode *inode = dentry->d_inode; |
246 | struct cifsInodeInfo *cinode = CIFS_I(inode); | 246 | struct cifsInodeInfo *cinode = CIFS_I(inode); |
247 | struct cifsFileInfo *cfile; | 247 | struct cifsFileInfo *cfile; |
248 | struct cifs_fid_locks *fdlocks; | ||
248 | 249 | ||
249 | cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | 250 | cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); |
250 | if (cfile == NULL) | 251 | if (cfile == NULL) |
251 | return cfile; | 252 | return cfile; |
252 | 253 | ||
254 | fdlocks = kzalloc(sizeof(struct cifs_fid_locks), GFP_KERNEL); | ||
255 | if (!fdlocks) { | ||
256 | kfree(cfile); | ||
257 | return NULL; | ||
258 | } | ||
259 | |||
260 | INIT_LIST_HEAD(&fdlocks->locks); | ||
261 | fdlocks->cfile = cfile; | ||
262 | cfile->llist = fdlocks; | ||
263 | mutex_lock(&cinode->lock_mutex); | ||
264 | list_add(&fdlocks->llist, &cinode->llist); | ||
265 | mutex_unlock(&cinode->lock_mutex); | ||
266 | |||
253 | cfile->count = 1; | 267 | cfile->count = 1; |
254 | cfile->pid = current->tgid; | 268 | cfile->pid = current->tgid; |
255 | cfile->uid = current_fsuid(); | 269 | cfile->uid = current_fsuid(); |
@@ -257,9 +271,8 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, | |||
257 | cfile->f_flags = file->f_flags; | 271 | cfile->f_flags = file->f_flags; |
258 | cfile->invalidHandle = false; | 272 | cfile->invalidHandle = false; |
259 | cfile->tlink = cifs_get_tlink(tlink); | 273 | cfile->tlink = cifs_get_tlink(tlink); |
260 | mutex_init(&cfile->fh_mutex); | ||
261 | INIT_WORK(&cfile->oplock_break, cifs_oplock_break); | 274 | INIT_WORK(&cfile->oplock_break, cifs_oplock_break); |
262 | INIT_LIST_HEAD(&cfile->llist); | 275 | mutex_init(&cfile->fh_mutex); |
263 | tlink_tcon(tlink)->ses->server->ops->set_fid(cfile, fid, oplock); | 276 | tlink_tcon(tlink)->ses->server->ops->set_fid(cfile, fid, oplock); |
264 | 277 | ||
265 | spin_lock(&cifs_file_list_lock); | 278 | spin_lock(&cifs_file_list_lock); |
@@ -336,15 +349,18 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) | |||
336 | free_xid(xid); | 349 | free_xid(xid); |
337 | } | 350 | } |
338 | 351 | ||
339 | /* Delete any outstanding lock records. We'll lose them when the file | 352 | /* |
353 | * Delete any outstanding lock records. We'll lose them when the file | ||
340 | * is closed anyway. | 354 | * is closed anyway. |
341 | */ | 355 | */ |
342 | mutex_lock(&cifsi->lock_mutex); | 356 | mutex_lock(&cifsi->lock_mutex); |
343 | list_for_each_entry_safe(li, tmp, &cifs_file->llist, llist) { | 357 | list_for_each_entry_safe(li, tmp, &cifs_file->llist->locks, llist) { |
344 | list_del(&li->llist); | 358 | list_del(&li->llist); |
345 | cifs_del_lock_waiters(li); | 359 | cifs_del_lock_waiters(li); |
346 | kfree(li); | 360 | kfree(li); |
347 | } | 361 | } |
362 | list_del(&cifs_file->llist->llist); | ||
363 | kfree(cifs_file->llist); | ||
348 | mutex_unlock(&cifsi->lock_mutex); | 364 | mutex_unlock(&cifsi->lock_mutex); |
349 | 365 | ||
350 | cifs_put_tlink(cifs_file->tlink); | 366 | cifs_put_tlink(cifs_file->tlink); |
@@ -691,25 +707,24 @@ cifs_del_lock_waiters(struct cifsLockInfo *lock) | |||
691 | } | 707 | } |
692 | 708 | ||
693 | static bool | 709 | static bool |
694 | cifs_find_fid_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, | 710 | cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset, |
695 | __u64 length, __u8 type, struct cifsFileInfo *cur, | 711 | __u64 length, __u8 type, struct cifsFileInfo *cfile, |
696 | struct cifsLockInfo **conf_lock) | 712 | struct cifsLockInfo **conf_lock) |
697 | { | 713 | { |
698 | struct cifsLockInfo *li; | 714 | struct cifsLockInfo *li; |
715 | struct cifsFileInfo *cur_cfile = fdlocks->cfile; | ||
699 | struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; | 716 | struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; |
700 | 717 | ||
701 | list_for_each_entry(li, &cfile->llist, llist) { | 718 | list_for_each_entry(li, &fdlocks->locks, llist) { |
702 | if (offset + length <= li->offset || | 719 | if (offset + length <= li->offset || |
703 | offset >= li->offset + li->length) | 720 | offset >= li->offset + li->length) |
704 | continue; | 721 | continue; |
705 | else if ((type & server->vals->shared_lock_type) && | 722 | if ((type & server->vals->shared_lock_type) && |
706 | ((server->ops->compare_fids(cur, cfile) && | 723 | ((server->ops->compare_fids(cfile, cur_cfile) && |
707 | current->tgid == li->pid) || type == li->type)) | 724 | current->tgid == li->pid) || type == li->type)) |
708 | continue; | 725 | continue; |
709 | else { | 726 | *conf_lock = li; |
710 | *conf_lock = li; | 727 | return true; |
711 | return true; | ||
712 | } | ||
713 | } | 728 | } |
714 | return false; | 729 | return false; |
715 | } | 730 | } |
@@ -719,17 +734,15 @@ cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length, | |||
719 | __u8 type, struct cifsLockInfo **conf_lock) | 734 | __u8 type, struct cifsLockInfo **conf_lock) |
720 | { | 735 | { |
721 | bool rc = false; | 736 | bool rc = false; |
722 | struct cifsFileInfo *fid, *tmp; | 737 | struct cifs_fid_locks *cur; |
723 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | 738 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); |
724 | 739 | ||
725 | spin_lock(&cifs_file_list_lock); | 740 | list_for_each_entry(cur, &cinode->llist, llist) { |
726 | list_for_each_entry_safe(fid, tmp, &cinode->openFileList, flist) { | 741 | rc = cifs_find_fid_lock_conflict(cur, offset, length, type, |
727 | rc = cifs_find_fid_lock_conflict(fid, offset, length, type, | ||
728 | cfile, conf_lock); | 742 | cfile, conf_lock); |
729 | if (rc) | 743 | if (rc) |
730 | break; | 744 | break; |
731 | } | 745 | } |
732 | spin_unlock(&cifs_file_list_lock); | ||
733 | 746 | ||
734 | return rc; | 747 | return rc; |
735 | } | 748 | } |
@@ -777,7 +790,7 @@ cifs_lock_add(struct cifsFileInfo *cfile, struct cifsLockInfo *lock) | |||
777 | { | 790 | { |
778 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | 791 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); |
779 | mutex_lock(&cinode->lock_mutex); | 792 | mutex_lock(&cinode->lock_mutex); |
780 | list_add_tail(&lock->llist, &cfile->llist); | 793 | list_add_tail(&lock->llist, &cfile->llist->locks); |
781 | mutex_unlock(&cinode->lock_mutex); | 794 | mutex_unlock(&cinode->lock_mutex); |
782 | } | 795 | } |
783 | 796 | ||
@@ -803,7 +816,7 @@ try_again: | |||
803 | exist = cifs_find_lock_conflict(cfile, lock->offset, lock->length, | 816 | exist = cifs_find_lock_conflict(cfile, lock->offset, lock->length, |
804 | lock->type, &conf_lock); | 817 | lock->type, &conf_lock); |
805 | if (!exist && cinode->can_cache_brlcks) { | 818 | if (!exist && cinode->can_cache_brlcks) { |
806 | list_add_tail(&lock->llist, &cfile->llist); | 819 | list_add_tail(&lock->llist, &cfile->llist->locks); |
807 | mutex_unlock(&cinode->lock_mutex); | 820 | mutex_unlock(&cinode->lock_mutex); |
808 | return rc; | 821 | return rc; |
809 | } | 822 | } |
@@ -937,7 +950,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
937 | for (i = 0; i < 2; i++) { | 950 | for (i = 0; i < 2; i++) { |
938 | cur = buf; | 951 | cur = buf; |
939 | num = 0; | 952 | num = 0; |
940 | list_for_each_entry_safe(li, tmp, &cfile->llist, llist) { | 953 | list_for_each_entry_safe(li, tmp, &cfile->llist->locks, llist) { |
941 | if (li->type != types[i]) | 954 | if (li->type != types[i]) |
942 | continue; | 955 | continue; |
943 | cur->Pid = cpu_to_le16(li->pid); | 956 | cur->Pid = cpu_to_le16(li->pid); |
@@ -1279,7 +1292,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, | |||
1279 | for (i = 0; i < 2; i++) { | 1292 | for (i = 0; i < 2; i++) { |
1280 | cur = buf; | 1293 | cur = buf; |
1281 | num = 0; | 1294 | num = 0; |
1282 | list_for_each_entry_safe(li, tmp, &cfile->llist, llist) { | 1295 | list_for_each_entry_safe(li, tmp, &cfile->llist->locks, llist) { |
1283 | if (flock->fl_start > li->offset || | 1296 | if (flock->fl_start > li->offset || |
1284 | (flock->fl_start + length) < | 1297 | (flock->fl_start + length) < |
1285 | (li->offset + li->length)) | 1298 | (li->offset + li->length)) |
@@ -1320,7 +1333,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, | |||
1320 | * list to the head of the file's list. | 1333 | * list to the head of the file's list. |
1321 | */ | 1334 | */ |
1322 | cifs_move_llist(&tmp_llist, | 1335 | cifs_move_llist(&tmp_llist, |
1323 | &cfile->llist); | 1336 | &cfile->llist->locks); |
1324 | rc = stored_rc; | 1337 | rc = stored_rc; |
1325 | } else | 1338 | } else |
1326 | /* | 1339 | /* |
@@ -1337,7 +1350,8 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, | |||
1337 | stored_rc = cifs_lockv(xid, tcon, cfile->fid.netfid, | 1350 | stored_rc = cifs_lockv(xid, tcon, cfile->fid.netfid, |
1338 | types[i], num, 0, buf); | 1351 | types[i], num, 0, buf); |
1339 | if (stored_rc) { | 1352 | if (stored_rc) { |
1340 | cifs_move_llist(&tmp_llist, &cfile->llist); | 1353 | cifs_move_llist(&tmp_llist, |
1354 | &cfile->llist->locks); | ||
1341 | rc = stored_rc; | 1355 | rc = stored_rc; |
1342 | } else | 1356 | } else |
1343 | cifs_free_llist(&tmp_llist); | 1357 | cifs_free_llist(&tmp_llist); |
@@ -1350,7 +1364,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, | |||
1350 | } | 1364 | } |
1351 | 1365 | ||
1352 | static int | 1366 | static int |
1353 | cifs_setlk(struct file *file, struct file_lock *flock, __u32 type, | 1367 | cifs_setlk(struct file *file, struct file_lock *flock, __u32 type, |
1354 | bool wait_flag, bool posix_lck, int lock, int unlock, | 1368 | bool wait_flag, bool posix_lck, int lock, int unlock, |
1355 | unsigned int xid) | 1369 | unsigned int xid) |
1356 | { | 1370 | { |
@@ -1359,7 +1373,6 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type, | |||
1359 | struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; | 1373 | struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; |
1360 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | 1374 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
1361 | struct TCP_Server_Info *server = tcon->ses->server; | 1375 | struct TCP_Server_Info *server = tcon->ses->server; |
1362 | __u16 netfid = cfile->fid.netfid; | ||
1363 | 1376 | ||
1364 | if (posix_lck) { | 1377 | if (posix_lck) { |
1365 | int posix_lock_type; | 1378 | int posix_lock_type; |
@@ -1376,9 +1389,9 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type, | |||
1376 | if (unlock == 1) | 1389 | if (unlock == 1) |
1377 | posix_lock_type = CIFS_UNLCK; | 1390 | posix_lock_type = CIFS_UNLCK; |
1378 | 1391 | ||
1379 | rc = CIFSSMBPosixLock(xid, tcon, netfid, current->tgid, | 1392 | rc = CIFSSMBPosixLock(xid, tcon, cfile->fid.netfid, |
1380 | flock->fl_start, length, NULL, | 1393 | current->tgid, flock->fl_start, length, |
1381 | posix_lock_type, wait_flag); | 1394 | NULL, posix_lock_type, wait_flag); |
1382 | goto out; | 1395 | goto out; |
1383 | } | 1396 | } |
1384 | 1397 | ||