diff options
| author | Pavel Shilovsky <piastry@etersoft.ru> | 2011-10-22 07:33:31 -0400 |
|---|---|---|
| committer | Steve French <smfrench@gmail.com> | 2011-10-24 14:11:52 -0400 |
| commit | 9ee305b70e09f5132c9723780ce10e69710b8bca (patch) | |
| tree | d739e9ba99cc523235404b7f5e38828ea6ed9536 | |
| parent | 4f6bcec910d45e4f46b1514977caa529bc69e645 (diff) | |
CIFS: Send as many mandatory unlock ranges at once as possible
that reduces a traffic and increases a performance.
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
Acked-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <smfrench@gmail.com>
| -rw-r--r-- | fs/cifs/cifsproto.h | 3 | ||||
| -rw-r--r-- | fs/cifs/cifssmb.c | 40 | ||||
| -rw-r--r-- | fs/cifs/file.c | 160 |
3 files changed, 167 insertions, 36 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 67c26cfe160d..ef4f631e4c01 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
| @@ -368,6 +368,9 @@ extern int CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon, | |||
| 368 | const struct nls_table *nls_codepage, | 368 | const struct nls_table *nls_codepage, |
| 369 | int remap_special_chars); | 369 | int remap_special_chars); |
| 370 | 370 | ||
| 371 | extern int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid, | ||
| 372 | const __u8 lock_type, const __u32 num_unlock, | ||
| 373 | const __u32 num_lock, LOCKING_ANDX_RANGE *buf); | ||
| 371 | extern int CIFSSMBLock(const int xid, struct cifs_tcon *tcon, | 374 | extern int CIFSSMBLock(const int xid, struct cifs_tcon *tcon, |
| 372 | const __u16 netfid, const __u32 netpid, const __u64 len, | 375 | const __u16 netfid, const __u32 netpid, const __u64 len, |
| 373 | const __u64 offset, const __u32 numUnlock, | 376 | const __u64 offset, const __u32 numUnlock, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 6a45a1769388..6600aa2d2ef3 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -2320,6 +2320,46 @@ CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms, | |||
| 2320 | return rc; | 2320 | return rc; |
| 2321 | } | 2321 | } |
| 2322 | 2322 | ||
| 2323 | int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid, | ||
| 2324 | const __u8 lock_type, const __u32 num_unlock, | ||
| 2325 | const __u32 num_lock, LOCKING_ANDX_RANGE *buf) | ||
| 2326 | { | ||
| 2327 | int rc = 0; | ||
| 2328 | LOCK_REQ *pSMB = NULL; | ||
| 2329 | struct kvec iov[2]; | ||
| 2330 | int resp_buf_type; | ||
| 2331 | __u16 count; | ||
| 2332 | |||
| 2333 | cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock); | ||
| 2334 | |||
| 2335 | rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB); | ||
| 2336 | if (rc) | ||
| 2337 | return rc; | ||
| 2338 | |||
| 2339 | pSMB->Timeout = 0; | ||
| 2340 | pSMB->NumberOfLocks = cpu_to_le16(num_lock); | ||
| 2341 | pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock); | ||
| 2342 | pSMB->LockType = lock_type; | ||
| 2343 | pSMB->AndXCommand = 0xFF; /* none */ | ||
| 2344 | pSMB->Fid = netfid; /* netfid stays le */ | ||
| 2345 | |||
| 2346 | count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE); | ||
| 2347 | inc_rfc1001_len(pSMB, count); | ||
| 2348 | pSMB->ByteCount = cpu_to_le16(count); | ||
| 2349 | |||
| 2350 | iov[0].iov_base = (char *)pSMB; | ||
| 2351 | iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 - | ||
| 2352 | (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE); | ||
| 2353 | iov[1].iov_base = (char *)buf; | ||
| 2354 | iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE); | ||
| 2355 | |||
| 2356 | cifs_stats_inc(&tcon->num_locks); | ||
| 2357 | rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP); | ||
| 2358 | if (rc) | ||
| 2359 | cFYI(1, "Send error in cifs_lockv = %d", rc); | ||
| 2360 | |||
| 2361 | return rc; | ||
| 2362 | } | ||
| 2323 | 2363 | ||
| 2324 | int | 2364 | int |
| 2325 | CIFSSMBLock(const int xid, struct cifs_tcon *tcon, | 2365 | CIFSSMBLock(const int xid, struct cifs_tcon *tcon, |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 805e2bd1dfd5..569184e6ee01 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -1057,6 +1057,128 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u8 type, | |||
| 1057 | return rc; | 1057 | return rc; |
| 1058 | } | 1058 | } |
| 1059 | 1059 | ||
| 1060 | static void | ||
| 1061 | cifs_move_llist(struct list_head *source, struct list_head *dest) | ||
| 1062 | { | ||
| 1063 | struct list_head *li, *tmp; | ||
| 1064 | list_for_each_safe(li, tmp, source) | ||
| 1065 | list_move(li, dest); | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | static void | ||
| 1069 | cifs_free_llist(struct list_head *llist) | ||
| 1070 | { | ||
| 1071 | struct cifsLockInfo *li, *tmp; | ||
| 1072 | list_for_each_entry_safe(li, tmp, llist, llist) { | ||
| 1073 | cifs_del_lock_waiters(li); | ||
| 1074 | list_del(&li->llist); | ||
| 1075 | kfree(li); | ||
| 1076 | } | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | static int | ||
| 1080 | cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid) | ||
| 1081 | { | ||
| 1082 | int rc = 0, stored_rc; | ||
| 1083 | int types[] = {LOCKING_ANDX_LARGE_FILES, | ||
| 1084 | LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES}; | ||
| 1085 | unsigned int i; | ||
| 1086 | unsigned int max_num, num; | ||
| 1087 | LOCKING_ANDX_RANGE *buf, *cur; | ||
| 1088 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | ||
| 1089 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | ||
| 1090 | struct cifsLockInfo *li, *tmp; | ||
| 1091 | __u64 length = 1 + flock->fl_end - flock->fl_start; | ||
| 1092 | struct list_head tmp_llist; | ||
| 1093 | |||
| 1094 | INIT_LIST_HEAD(&tmp_llist); | ||
| 1095 | |||
| 1096 | max_num = (tcon->ses->server->maxBuf - sizeof(struct smb_hdr)) / | ||
| 1097 | sizeof(LOCKING_ANDX_RANGE); | ||
| 1098 | buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL); | ||
| 1099 | if (!buf) | ||
| 1100 | return -ENOMEM; | ||
| 1101 | |||
| 1102 | mutex_lock(&cinode->lock_mutex); | ||
| 1103 | for (i = 0; i < 2; i++) { | ||
| 1104 | cur = buf; | ||
| 1105 | num = 0; | ||
| 1106 | list_for_each_entry_safe(li, tmp, &cinode->llist, llist) { | ||
| 1107 | if (flock->fl_start > li->offset || | ||
| 1108 | (flock->fl_start + length) < | ||
| 1109 | (li->offset + li->length)) | ||
| 1110 | continue; | ||
| 1111 | if (current->tgid != li->pid) | ||
| 1112 | continue; | ||
| 1113 | if (cfile->netfid != li->netfid) | ||
| 1114 | continue; | ||
| 1115 | if (types[i] != li->type) | ||
| 1116 | continue; | ||
| 1117 | if (!cinode->can_cache_brlcks) { | ||
| 1118 | cur->Pid = cpu_to_le16(li->pid); | ||
| 1119 | cur->LengthLow = cpu_to_le32((u32)li->length); | ||
| 1120 | cur->LengthHigh = | ||
| 1121 | cpu_to_le32((u32)(li->length>>32)); | ||
| 1122 | cur->OffsetLow = cpu_to_le32((u32)li->offset); | ||
| 1123 | cur->OffsetHigh = | ||
| 1124 | cpu_to_le32((u32)(li->offset>>32)); | ||
| 1125 | /* | ||
| 1126 | * We need to save a lock here to let us add | ||
| 1127 | * it again to the inode list if the unlock | ||
| 1128 | * range request fails on the server. | ||
| 1129 | */ | ||
| 1130 | list_move(&li->llist, &tmp_llist); | ||
| 1131 | if (++num == max_num) { | ||
| 1132 | stored_rc = cifs_lockv(xid, tcon, | ||
| 1133 | cfile->netfid, | ||
| 1134 | li->type, num, | ||
| 1135 | 0, buf); | ||
| 1136 | if (stored_rc) { | ||
| 1137 | /* | ||
| 1138 | * We failed on the unlock range | ||
| 1139 | * request - add all locks from | ||
| 1140 | * the tmp list to the head of | ||
| 1141 | * the inode list. | ||
| 1142 | */ | ||
| 1143 | cifs_move_llist(&tmp_llist, | ||
| 1144 | &cinode->llist); | ||
| 1145 | rc = stored_rc; | ||
| 1146 | } else | ||
| 1147 | /* | ||
| 1148 | * The unlock range request | ||
| 1149 | * succeed - free the tmp list. | ||
| 1150 | */ | ||
| 1151 | cifs_free_llist(&tmp_llist); | ||
| 1152 | cur = buf; | ||
| 1153 | num = 0; | ||
| 1154 | } else | ||
| 1155 | cur++; | ||
| 1156 | } else { | ||
| 1157 | /* | ||
| 1158 | * We can cache brlock requests - simply remove | ||
| 1159 | * a lock from the inode list. | ||
| 1160 | */ | ||
| 1161 | list_del(&li->llist); | ||
| 1162 | cifs_del_lock_waiters(li); | ||
| 1163 | kfree(li); | ||
| 1164 | } | ||
| 1165 | } | ||
| 1166 | if (num) { | ||
| 1167 | stored_rc = cifs_lockv(xid, tcon, cfile->netfid, | ||
| 1168 | types[i], num, 0, buf); | ||
| 1169 | if (stored_rc) { | ||
| 1170 | cifs_move_llist(&tmp_llist, &cinode->llist); | ||
| 1171 | rc = stored_rc; | ||
| 1172 | } else | ||
| 1173 | cifs_free_llist(&tmp_llist); | ||
| 1174 | } | ||
| 1175 | } | ||
| 1176 | |||
| 1177 | mutex_unlock(&cinode->lock_mutex); | ||
| 1178 | kfree(buf); | ||
| 1179 | return rc; | ||
| 1180 | } | ||
| 1181 | |||
| 1060 | static int | 1182 | static int |
| 1061 | cifs_setlk(struct file *file, struct file_lock *flock, __u8 type, | 1183 | cifs_setlk(struct file *file, struct file_lock *flock, __u8 type, |
| 1062 | bool wait_flag, bool posix_lck, int lock, int unlock, int xid) | 1184 | bool wait_flag, bool posix_lck, int lock, int unlock, int xid) |
| @@ -1104,43 +1226,9 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u8 type, | |||
| 1104 | rc = cifs_lock_add(cinode, length, flock->fl_start, | 1226 | rc = cifs_lock_add(cinode, length, flock->fl_start, |
| 1105 | type, netfid); | 1227 | type, netfid); |
| 1106 | } | 1228 | } |
| 1107 | } else if (unlock) { | 1229 | } else if (unlock) |
| 1108 | /* | 1230 | rc = cifs_unlock_range(cfile, flock, xid); |
| 1109 | * For each stored lock that this unlock overlaps completely, | ||
| 1110 | * unlock it. | ||
| 1111 | */ | ||
| 1112 | int stored_rc = 0; | ||
| 1113 | struct cifsLockInfo *li, *tmp; | ||
| 1114 | |||
| 1115 | mutex_lock(&cinode->lock_mutex); | ||
| 1116 | list_for_each_entry_safe(li, tmp, &cinode->llist, llist) { | ||
| 1117 | if (flock->fl_start > li->offset || | ||
| 1118 | (flock->fl_start + length) < | ||
| 1119 | (li->offset + li->length)) | ||
| 1120 | continue; | ||
| 1121 | if (current->tgid != li->pid) | ||
| 1122 | continue; | ||
| 1123 | if (cfile->netfid != li->netfid) | ||
| 1124 | continue; | ||
| 1125 | |||
| 1126 | if (!cinode->can_cache_brlcks) | ||
| 1127 | stored_rc = CIFSSMBLock(xid, tcon, netfid, | ||
| 1128 | current->tgid, | ||
| 1129 | li->length, li->offset, | ||
| 1130 | 1, 0, li->type, 0, 0); | ||
| 1131 | else | ||
| 1132 | stored_rc = 0; | ||
| 1133 | 1231 | ||
| 1134 | if (stored_rc) | ||
| 1135 | rc = stored_rc; | ||
| 1136 | else { | ||
| 1137 | list_del(&li->llist); | ||
| 1138 | cifs_del_lock_waiters(li); | ||
| 1139 | kfree(li); | ||
| 1140 | } | ||
| 1141 | } | ||
| 1142 | mutex_unlock(&cinode->lock_mutex); | ||
| 1143 | } | ||
| 1144 | out: | 1232 | out: |
| 1145 | if (flock->fl_flags & FL_POSIX) | 1233 | if (flock->fl_flags & FL_POSIX) |
| 1146 | posix_lock_file_wait(file, flock); | 1234 | posix_lock_file_wait(file, flock); |
