diff options
Diffstat (limited to 'fs')
66 files changed, 921 insertions, 857 deletions
diff --git a/fs/9p/fid.c b/fs/9p/fid.c index 358563689064..6406f896bf95 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c | |||
| @@ -242,7 +242,8 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry) | |||
| 242 | } | 242 | } |
| 243 | kfree(wnames); | 243 | kfree(wnames); |
| 244 | fid_out: | 244 | fid_out: |
| 245 | v9fs_fid_add(dentry, fid); | 245 | if (!IS_ERR(fid)) |
| 246 | v9fs_fid_add(dentry, fid); | ||
| 246 | err_out: | 247 | err_out: |
| 247 | up_read(&v9ses->rename_sem); | 248 | up_read(&v9ses->rename_sem); |
| 248 | return fid; | 249 | return fid; |
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index 16c8a2a98c1b..899f168fd19c 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c | |||
| @@ -292,9 +292,11 @@ int v9fs_dir_release(struct inode *inode, struct file *filp) | |||
| 292 | 292 | ||
| 293 | fid = filp->private_data; | 293 | fid = filp->private_data; |
| 294 | P9_DPRINTK(P9_DEBUG_VFS, | 294 | P9_DPRINTK(P9_DEBUG_VFS, |
| 295 | "inode: %p filp: %p fid: %d\n", inode, filp, fid->fid); | 295 | "v9fs_dir_release: inode: %p filp: %p fid: %d\n", |
| 296 | inode, filp, fid ? fid->fid : -1); | ||
| 296 | filemap_write_and_wait(inode->i_mapping); | 297 | filemap_write_and_wait(inode->i_mapping); |
| 297 | p9_client_clunk(fid); | 298 | if (fid) |
| 299 | p9_client_clunk(fid); | ||
| 298 | return 0; | 300 | return 0; |
| 299 | } | 301 | } |
| 300 | 302 | ||
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index c7c23eab9440..9e670d527646 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
| @@ -730,7 +730,10 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode, | |||
| 730 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); | 730 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); |
| 731 | goto error; | 731 | goto error; |
| 732 | } | 732 | } |
| 733 | dentry->d_op = &v9fs_cached_dentry_operations; | 733 | if (v9ses->cache) |
| 734 | dentry->d_op = &v9fs_cached_dentry_operations; | ||
| 735 | else | ||
| 736 | dentry->d_op = &v9fs_dentry_operations; | ||
| 734 | d_instantiate(dentry, inode); | 737 | d_instantiate(dentry, inode); |
| 735 | err = v9fs_fid_add(dentry, fid); | 738 | err = v9fs_fid_add(dentry, fid); |
| 736 | if (err < 0) | 739 | if (err < 0) |
| @@ -1128,6 +1131,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
| 1128 | v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb); | 1131 | v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb); |
| 1129 | generic_fillattr(dentry->d_inode, stat); | 1132 | generic_fillattr(dentry->d_inode, stat); |
| 1130 | 1133 | ||
| 1134 | p9stat_free(st); | ||
| 1131 | kfree(st); | 1135 | kfree(st); |
| 1132 | return 0; | 1136 | return 0; |
| 1133 | } | 1137 | } |
| @@ -1489,6 +1493,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) | |||
| 1489 | 1493 | ||
| 1490 | retval = strnlen(buffer, buflen); | 1494 | retval = strnlen(buffer, buflen); |
| 1491 | done: | 1495 | done: |
| 1496 | p9stat_free(st); | ||
| 1492 | kfree(st); | 1497 | kfree(st); |
| 1493 | return retval; | 1498 | return retval; |
| 1494 | } | 1499 | } |
| @@ -1942,7 +1947,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotu = { | |||
| 1942 | .unlink = v9fs_vfs_unlink, | 1947 | .unlink = v9fs_vfs_unlink, |
| 1943 | .mkdir = v9fs_vfs_mkdir, | 1948 | .mkdir = v9fs_vfs_mkdir, |
| 1944 | .rmdir = v9fs_vfs_rmdir, | 1949 | .rmdir = v9fs_vfs_rmdir, |
| 1945 | .mknod = v9fs_vfs_mknod_dotl, | 1950 | .mknod = v9fs_vfs_mknod, |
| 1946 | .rename = v9fs_vfs_rename, | 1951 | .rename = v9fs_vfs_rename, |
| 1947 | .getattr = v9fs_vfs_getattr, | 1952 | .getattr = v9fs_vfs_getattr, |
| 1948 | .setattr = v9fs_vfs_setattr, | 1953 | .setattr = v9fs_vfs_setattr, |
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index f9311077de68..1d12ba0ed3db 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c | |||
| @@ -122,6 +122,10 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags, | |||
| 122 | fid = v9fs_session_init(v9ses, dev_name, data); | 122 | fid = v9fs_session_init(v9ses, dev_name, data); |
| 123 | if (IS_ERR(fid)) { | 123 | if (IS_ERR(fid)) { |
| 124 | retval = PTR_ERR(fid); | 124 | retval = PTR_ERR(fid); |
| 125 | /* | ||
| 126 | * we need to call session_close to tear down some | ||
| 127 | * of the data structure setup by session_init | ||
| 128 | */ | ||
| 125 | goto close_session; | 129 | goto close_session; |
| 126 | } | 130 | } |
| 127 | 131 | ||
| @@ -144,7 +148,6 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags, | |||
| 144 | retval = -ENOMEM; | 148 | retval = -ENOMEM; |
| 145 | goto release_sb; | 149 | goto release_sb; |
| 146 | } | 150 | } |
| 147 | |||
| 148 | sb->s_root = root; | 151 | sb->s_root = root; |
| 149 | 152 | ||
| 150 | if (v9fs_proto_dotl(v9ses)) { | 153 | if (v9fs_proto_dotl(v9ses)) { |
| @@ -152,7 +155,7 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags, | |||
| 152 | st = p9_client_getattr_dotl(fid, P9_STATS_BASIC); | 155 | st = p9_client_getattr_dotl(fid, P9_STATS_BASIC); |
| 153 | if (IS_ERR(st)) { | 156 | if (IS_ERR(st)) { |
| 154 | retval = PTR_ERR(st); | 157 | retval = PTR_ERR(st); |
| 155 | goto clunk_fid; | 158 | goto release_sb; |
| 156 | } | 159 | } |
| 157 | 160 | ||
| 158 | v9fs_stat2inode_dotl(st, root->d_inode); | 161 | v9fs_stat2inode_dotl(st, root->d_inode); |
| @@ -162,7 +165,7 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags, | |||
| 162 | st = p9_client_stat(fid); | 165 | st = p9_client_stat(fid); |
| 163 | if (IS_ERR(st)) { | 166 | if (IS_ERR(st)) { |
| 164 | retval = PTR_ERR(st); | 167 | retval = PTR_ERR(st); |
| 165 | goto clunk_fid; | 168 | goto release_sb; |
| 166 | } | 169 | } |
| 167 | 170 | ||
| 168 | root->d_inode->i_ino = v9fs_qid2ino(&st->qid); | 171 | root->d_inode->i_ino = v9fs_qid2ino(&st->qid); |
| @@ -174,19 +177,24 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags, | |||
| 174 | 177 | ||
| 175 | v9fs_fid_add(root, fid); | 178 | v9fs_fid_add(root, fid); |
| 176 | 179 | ||
| 177 | P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n"); | 180 | P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n"); |
| 178 | simple_set_mnt(mnt, sb); | 181 | simple_set_mnt(mnt, sb); |
| 179 | return 0; | 182 | return 0; |
| 180 | 183 | ||
| 181 | clunk_fid: | 184 | clunk_fid: |
| 182 | p9_client_clunk(fid); | 185 | p9_client_clunk(fid); |
| 183 | |||
| 184 | close_session: | 186 | close_session: |
| 185 | v9fs_session_close(v9ses); | 187 | v9fs_session_close(v9ses); |
| 186 | kfree(v9ses); | 188 | kfree(v9ses); |
| 187 | return retval; | 189 | return retval; |
| 188 | |||
| 189 | release_sb: | 190 | release_sb: |
| 191 | /* | ||
| 192 | * we will do the session_close and root dentry release | ||
| 193 | * in the below call. But we need to clunk fid, because we haven't | ||
| 194 | * attached the fid to dentry so it won't get clunked | ||
| 195 | * automatically. | ||
| 196 | */ | ||
| 197 | p9_client_clunk(fid); | ||
| 190 | deactivate_locked_super(sb); | 198 | deactivate_locked_super(sb); |
| 191 | return retval; | 199 | return retval; |
| 192 | } | 200 | } |
| @@ -1659,6 +1659,9 @@ long do_io_submit(aio_context_t ctx_id, long nr, | |||
| 1659 | if (unlikely(nr < 0)) | 1659 | if (unlikely(nr < 0)) |
| 1660 | return -EINVAL; | 1660 | return -EINVAL; |
| 1661 | 1661 | ||
| 1662 | if (unlikely(nr > LONG_MAX/sizeof(*iocbpp))) | ||
| 1663 | nr = LONG_MAX/sizeof(*iocbpp); | ||
| 1664 | |||
| 1662 | if (unlikely(!access_ok(VERIFY_READ, iocbpp, (nr*sizeof(*iocbpp))))) | 1665 | if (unlikely(!access_ok(VERIFY_READ, iocbpp, (nr*sizeof(*iocbpp))))) |
| 1663 | return -EFAULT; | 1666 | return -EFAULT; |
| 1664 | 1667 | ||
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index a7528b913936..fd0cc0bf9a40 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c | |||
| @@ -724,7 +724,7 @@ static int __init init_misc_binfmt(void) | |||
| 724 | { | 724 | { |
| 725 | int err = register_filesystem(&bm_fs_type); | 725 | int err = register_filesystem(&bm_fs_type); |
| 726 | if (!err) { | 726 | if (!err) { |
| 727 | err = register_binfmt(&misc_format); | 727 | err = insert_binfmt(&misc_format); |
| 728 | if (err) | 728 | if (err) |
| 729 | unregister_filesystem(&bm_fs_type); | 729 | unregister_filesystem(&bm_fs_type); |
| 730 | } | 730 | } |
diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c index 612a5c38d3c1..4d0ff5ee27b8 100644 --- a/fs/bio-integrity.c +++ b/fs/bio-integrity.c | |||
| @@ -413,10 +413,10 @@ int bio_integrity_prep(struct bio *bio) | |||
| 413 | 413 | ||
| 414 | /* Allocate kernel buffer for protection data */ | 414 | /* Allocate kernel buffer for protection data */ |
| 415 | len = sectors * blk_integrity_tuple_size(bi); | 415 | len = sectors * blk_integrity_tuple_size(bi); |
| 416 | buf = kmalloc(len, GFP_NOIO | __GFP_NOFAIL | q->bounce_gfp); | 416 | buf = kmalloc(len, GFP_NOIO | q->bounce_gfp); |
| 417 | if (unlikely(buf == NULL)) { | 417 | if (unlikely(buf == NULL)) { |
| 418 | printk(KERN_ERR "could not allocate integrity buffer\n"); | 418 | printk(KERN_ERR "could not allocate integrity buffer\n"); |
| 419 | return -EIO; | 419 | return -ENOMEM; |
| 420 | } | 420 | } |
| 421 | 421 | ||
| 422 | end = (((unsigned long) buf) + len + PAGE_SIZE - 1) >> PAGE_SHIFT; | 422 | end = (((unsigned long) buf) + len + PAGE_SIZE - 1) >> PAGE_SHIFT; |
diff --git a/fs/ceph/Kconfig b/fs/ceph/Kconfig index bc87b9c1d27e..0fcd2640c23f 100644 --- a/fs/ceph/Kconfig +++ b/fs/ceph/Kconfig | |||
| @@ -3,6 +3,7 @@ config CEPH_FS | |||
| 3 | depends on INET && EXPERIMENTAL | 3 | depends on INET && EXPERIMENTAL |
| 4 | select LIBCRC32C | 4 | select LIBCRC32C |
| 5 | select CRYPTO_AES | 5 | select CRYPTO_AES |
| 6 | select CRYPTO | ||
| 6 | help | 7 | help |
| 7 | Choose Y or M here to include support for mounting the | 8 | Choose Y or M here to include support for mounting the |
| 8 | experimental Ceph distributed file system. Ceph is an extremely | 9 | experimental Ceph distributed file system. Ceph is an extremely |
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 4cfce1ee31fa..efbc604001c8 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c | |||
| @@ -411,8 +411,8 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc) | |||
| 411 | if (i_size < page_off + len) | 411 | if (i_size < page_off + len) |
| 412 | len = i_size - page_off; | 412 | len = i_size - page_off; |
| 413 | 413 | ||
| 414 | dout("writepage %p page %p index %lu on %llu~%u\n", | 414 | dout("writepage %p page %p index %lu on %llu~%u snapc %p\n", |
| 415 | inode, page, page->index, page_off, len); | 415 | inode, page, page->index, page_off, len, snapc); |
| 416 | 416 | ||
| 417 | writeback_stat = atomic_long_inc_return(&client->writeback_count); | 417 | writeback_stat = atomic_long_inc_return(&client->writeback_count); |
| 418 | if (writeback_stat > | 418 | if (writeback_stat > |
| @@ -766,7 +766,8 @@ get_more_pages: | |||
| 766 | /* ok */ | 766 | /* ok */ |
| 767 | if (locked_pages == 0) { | 767 | if (locked_pages == 0) { |
| 768 | /* prepare async write request */ | 768 | /* prepare async write request */ |
| 769 | offset = page->index << PAGE_CACHE_SHIFT; | 769 | offset = (unsigned long long)page->index |
| 770 | << PAGE_CACHE_SHIFT; | ||
| 770 | len = wsize; | 771 | len = wsize; |
| 771 | req = ceph_osdc_new_request(&client->osdc, | 772 | req = ceph_osdc_new_request(&client->osdc, |
| 772 | &ci->i_layout, | 773 | &ci->i_layout, |
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index a2069b6680ae..73c153092f72 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c | |||
| @@ -814,7 +814,7 @@ int __ceph_caps_used(struct ceph_inode_info *ci) | |||
| 814 | used |= CEPH_CAP_PIN; | 814 | used |= CEPH_CAP_PIN; |
| 815 | if (ci->i_rd_ref) | 815 | if (ci->i_rd_ref) |
| 816 | used |= CEPH_CAP_FILE_RD; | 816 | used |= CEPH_CAP_FILE_RD; |
| 817 | if (ci->i_rdcache_ref || ci->i_rdcache_gen) | 817 | if (ci->i_rdcache_ref || ci->vfs_inode.i_data.nrpages) |
| 818 | used |= CEPH_CAP_FILE_CACHE; | 818 | used |= CEPH_CAP_FILE_CACHE; |
| 819 | if (ci->i_wr_ref) | 819 | if (ci->i_wr_ref) |
| 820 | used |= CEPH_CAP_FILE_WR; | 820 | used |= CEPH_CAP_FILE_WR; |
| @@ -1195,10 +1195,14 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap, | |||
| 1195 | * asynchronously back to the MDS once sync writes complete and dirty | 1195 | * asynchronously back to the MDS once sync writes complete and dirty |
| 1196 | * data is written out. | 1196 | * data is written out. |
| 1197 | * | 1197 | * |
| 1198 | * Unless @again is true, skip cap_snaps that were already sent to | ||
| 1199 | * the MDS (i.e., during this session). | ||
| 1200 | * | ||
| 1198 | * Called under i_lock. Takes s_mutex as needed. | 1201 | * Called under i_lock. Takes s_mutex as needed. |
| 1199 | */ | 1202 | */ |
| 1200 | void __ceph_flush_snaps(struct ceph_inode_info *ci, | 1203 | void __ceph_flush_snaps(struct ceph_inode_info *ci, |
| 1201 | struct ceph_mds_session **psession) | 1204 | struct ceph_mds_session **psession, |
| 1205 | int again) | ||
| 1202 | __releases(ci->vfs_inode->i_lock) | 1206 | __releases(ci->vfs_inode->i_lock) |
| 1203 | __acquires(ci->vfs_inode->i_lock) | 1207 | __acquires(ci->vfs_inode->i_lock) |
| 1204 | { | 1208 | { |
| @@ -1227,7 +1231,7 @@ retry: | |||
| 1227 | * pages to be written out. | 1231 | * pages to be written out. |
| 1228 | */ | 1232 | */ |
| 1229 | if (capsnap->dirty_pages || capsnap->writing) | 1233 | if (capsnap->dirty_pages || capsnap->writing) |
| 1230 | continue; | 1234 | break; |
| 1231 | 1235 | ||
| 1232 | /* | 1236 | /* |
| 1233 | * if cap writeback already occurred, we should have dropped | 1237 | * if cap writeback already occurred, we should have dropped |
| @@ -1240,6 +1244,13 @@ retry: | |||
| 1240 | dout("no auth cap (migrating?), doing nothing\n"); | 1244 | dout("no auth cap (migrating?), doing nothing\n"); |
| 1241 | goto out; | 1245 | goto out; |
| 1242 | } | 1246 | } |
| 1247 | |||
| 1248 | /* only flush each capsnap once */ | ||
| 1249 | if (!again && !list_empty(&capsnap->flushing_item)) { | ||
| 1250 | dout("already flushed %p, skipping\n", capsnap); | ||
| 1251 | continue; | ||
| 1252 | } | ||
| 1253 | |||
| 1243 | mds = ci->i_auth_cap->session->s_mds; | 1254 | mds = ci->i_auth_cap->session->s_mds; |
| 1244 | mseq = ci->i_auth_cap->mseq; | 1255 | mseq = ci->i_auth_cap->mseq; |
| 1245 | 1256 | ||
| @@ -1276,8 +1287,8 @@ retry: | |||
| 1276 | &session->s_cap_snaps_flushing); | 1287 | &session->s_cap_snaps_flushing); |
| 1277 | spin_unlock(&inode->i_lock); | 1288 | spin_unlock(&inode->i_lock); |
| 1278 | 1289 | ||
| 1279 | dout("flush_snaps %p cap_snap %p follows %lld size %llu\n", | 1290 | dout("flush_snaps %p cap_snap %p follows %lld tid %llu\n", |
| 1280 | inode, capsnap, next_follows, capsnap->size); | 1291 | inode, capsnap, capsnap->follows, capsnap->flush_tid); |
| 1281 | send_cap_msg(session, ceph_vino(inode).ino, 0, | 1292 | send_cap_msg(session, ceph_vino(inode).ino, 0, |
| 1282 | CEPH_CAP_OP_FLUSHSNAP, capsnap->issued, 0, | 1293 | CEPH_CAP_OP_FLUSHSNAP, capsnap->issued, 0, |
| 1283 | capsnap->dirty, 0, capsnap->flush_tid, 0, mseq, | 1294 | capsnap->dirty, 0, capsnap->flush_tid, 0, mseq, |
| @@ -1314,7 +1325,7 @@ static void ceph_flush_snaps(struct ceph_inode_info *ci) | |||
| 1314 | struct inode *inode = &ci->vfs_inode; | 1325 | struct inode *inode = &ci->vfs_inode; |
| 1315 | 1326 | ||
| 1316 | spin_lock(&inode->i_lock); | 1327 | spin_lock(&inode->i_lock); |
| 1317 | __ceph_flush_snaps(ci, NULL); | 1328 | __ceph_flush_snaps(ci, NULL, 0); |
| 1318 | spin_unlock(&inode->i_lock); | 1329 | spin_unlock(&inode->i_lock); |
| 1319 | } | 1330 | } |
| 1320 | 1331 | ||
| @@ -1477,7 +1488,7 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags, | |||
| 1477 | 1488 | ||
| 1478 | /* flush snaps first time around only */ | 1489 | /* flush snaps first time around only */ |
| 1479 | if (!list_empty(&ci->i_cap_snaps)) | 1490 | if (!list_empty(&ci->i_cap_snaps)) |
| 1480 | __ceph_flush_snaps(ci, &session); | 1491 | __ceph_flush_snaps(ci, &session, 0); |
| 1481 | goto retry_locked; | 1492 | goto retry_locked; |
| 1482 | retry: | 1493 | retry: |
| 1483 | spin_lock(&inode->i_lock); | 1494 | spin_lock(&inode->i_lock); |
| @@ -1894,7 +1905,7 @@ static void kick_flushing_capsnaps(struct ceph_mds_client *mdsc, | |||
| 1894 | if (cap && cap->session == session) { | 1905 | if (cap && cap->session == session) { |
| 1895 | dout("kick_flushing_caps %p cap %p capsnap %p\n", inode, | 1906 | dout("kick_flushing_caps %p cap %p capsnap %p\n", inode, |
| 1896 | cap, capsnap); | 1907 | cap, capsnap); |
| 1897 | __ceph_flush_snaps(ci, &session); | 1908 | __ceph_flush_snaps(ci, &session, 1); |
| 1898 | } else { | 1909 | } else { |
| 1899 | pr_err("%p auth cap %p not mds%d ???\n", inode, | 1910 | pr_err("%p auth cap %p not mds%d ???\n", inode, |
| 1900 | cap, session->s_mds); | 1911 | cap, session->s_mds); |
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 6e4f43ff23ec..a1986eb52045 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
| @@ -1021,11 +1021,15 @@ out_touch: | |||
| 1021 | static void ceph_dentry_release(struct dentry *dentry) | 1021 | static void ceph_dentry_release(struct dentry *dentry) |
| 1022 | { | 1022 | { |
| 1023 | struct ceph_dentry_info *di = ceph_dentry(dentry); | 1023 | struct ceph_dentry_info *di = ceph_dentry(dentry); |
| 1024 | struct inode *parent_inode = dentry->d_parent->d_inode; | 1024 | struct inode *parent_inode = NULL; |
| 1025 | u64 snapid = ceph_snap(parent_inode); | 1025 | u64 snapid = CEPH_NOSNAP; |
| 1026 | 1026 | ||
| 1027 | if (!IS_ROOT(dentry)) { | ||
| 1028 | parent_inode = dentry->d_parent->d_inode; | ||
| 1029 | if (parent_inode) | ||
| 1030 | snapid = ceph_snap(parent_inode); | ||
| 1031 | } | ||
| 1027 | dout("dentry_release %p parent %p\n", dentry, parent_inode); | 1032 | dout("dentry_release %p parent %p\n", dentry, parent_inode); |
| 1028 | |||
| 1029 | if (parent_inode && snapid != CEPH_SNAPDIR) { | 1033 | if (parent_inode && snapid != CEPH_SNAPDIR) { |
| 1030 | struct ceph_inode_info *ci = ceph_inode(parent_inode); | 1034 | struct ceph_inode_info *ci = ceph_inode(parent_inode); |
| 1031 | 1035 | ||
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index e7cca414da03..62377ec37edf 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
| @@ -845,7 +845,7 @@ static void ceph_set_dentry_offset(struct dentry *dn) | |||
| 845 | * the caller) if we fail. | 845 | * the caller) if we fail. |
| 846 | */ | 846 | */ |
| 847 | static struct dentry *splice_dentry(struct dentry *dn, struct inode *in, | 847 | static struct dentry *splice_dentry(struct dentry *dn, struct inode *in, |
| 848 | bool *prehash) | 848 | bool *prehash, bool set_offset) |
| 849 | { | 849 | { |
| 850 | struct dentry *realdn; | 850 | struct dentry *realdn; |
| 851 | 851 | ||
| @@ -877,7 +877,8 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in, | |||
| 877 | } | 877 | } |
| 878 | if ((!prehash || *prehash) && d_unhashed(dn)) | 878 | if ((!prehash || *prehash) && d_unhashed(dn)) |
| 879 | d_rehash(dn); | 879 | d_rehash(dn); |
| 880 | ceph_set_dentry_offset(dn); | 880 | if (set_offset) |
| 881 | ceph_set_dentry_offset(dn); | ||
| 881 | out: | 882 | out: |
| 882 | return dn; | 883 | return dn; |
| 883 | } | 884 | } |
| @@ -1062,7 +1063,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, | |||
| 1062 | d_delete(dn); | 1063 | d_delete(dn); |
| 1063 | goto done; | 1064 | goto done; |
| 1064 | } | 1065 | } |
| 1065 | dn = splice_dentry(dn, in, &have_lease); | 1066 | dn = splice_dentry(dn, in, &have_lease, true); |
| 1066 | if (IS_ERR(dn)) { | 1067 | if (IS_ERR(dn)) { |
| 1067 | err = PTR_ERR(dn); | 1068 | err = PTR_ERR(dn); |
| 1068 | goto done; | 1069 | goto done; |
| @@ -1105,7 +1106,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, | |||
| 1105 | goto done; | 1106 | goto done; |
| 1106 | } | 1107 | } |
| 1107 | dout(" linking snapped dir %p to dn %p\n", in, dn); | 1108 | dout(" linking snapped dir %p to dn %p\n", in, dn); |
| 1108 | dn = splice_dentry(dn, in, NULL); | 1109 | dn = splice_dentry(dn, in, NULL, true); |
| 1109 | if (IS_ERR(dn)) { | 1110 | if (IS_ERR(dn)) { |
| 1110 | err = PTR_ERR(dn); | 1111 | err = PTR_ERR(dn); |
| 1111 | goto done; | 1112 | goto done; |
| @@ -1237,7 +1238,7 @@ retry_lookup: | |||
| 1237 | err = PTR_ERR(in); | 1238 | err = PTR_ERR(in); |
| 1238 | goto out; | 1239 | goto out; |
| 1239 | } | 1240 | } |
| 1240 | dn = splice_dentry(dn, in, NULL); | 1241 | dn = splice_dentry(dn, in, NULL, false); |
| 1241 | if (IS_ERR(dn)) | 1242 | if (IS_ERR(dn)) |
| 1242 | dn = NULL; | 1243 | dn = NULL; |
| 1243 | } | 1244 | } |
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index f091b1351786..fad95f8f2608 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
| @@ -2374,6 +2374,8 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap, | |||
| 2374 | num_fcntl_locks, | 2374 | num_fcntl_locks, |
| 2375 | num_flock_locks); | 2375 | num_flock_locks); |
| 2376 | unlock_kernel(); | 2376 | unlock_kernel(); |
| 2377 | } else { | ||
| 2378 | err = ceph_pagelist_append(pagelist, &rec, reclen); | ||
| 2377 | } | 2379 | } |
| 2378 | 2380 | ||
| 2379 | out_free: | 2381 | out_free: |
diff --git a/fs/ceph/pagelist.c b/fs/ceph/pagelist.c index b6859f47d364..46a368b6dce5 100644 --- a/fs/ceph/pagelist.c +++ b/fs/ceph/pagelist.c | |||
| @@ -5,10 +5,18 @@ | |||
| 5 | 5 | ||
| 6 | #include "pagelist.h" | 6 | #include "pagelist.h" |
| 7 | 7 | ||
| 8 | static void ceph_pagelist_unmap_tail(struct ceph_pagelist *pl) | ||
| 9 | { | ||
| 10 | struct page *page = list_entry(pl->head.prev, struct page, | ||
| 11 | lru); | ||
| 12 | kunmap(page); | ||
| 13 | } | ||
| 14 | |||
| 8 | int ceph_pagelist_release(struct ceph_pagelist *pl) | 15 | int ceph_pagelist_release(struct ceph_pagelist *pl) |
| 9 | { | 16 | { |
| 10 | if (pl->mapped_tail) | 17 | if (pl->mapped_tail) |
| 11 | kunmap(pl->mapped_tail); | 18 | ceph_pagelist_unmap_tail(pl); |
| 19 | |||
| 12 | while (!list_empty(&pl->head)) { | 20 | while (!list_empty(&pl->head)) { |
| 13 | struct page *page = list_first_entry(&pl->head, struct page, | 21 | struct page *page = list_first_entry(&pl->head, struct page, |
| 14 | lru); | 22 | lru); |
| @@ -26,7 +34,7 @@ static int ceph_pagelist_addpage(struct ceph_pagelist *pl) | |||
| 26 | pl->room += PAGE_SIZE; | 34 | pl->room += PAGE_SIZE; |
| 27 | list_add_tail(&page->lru, &pl->head); | 35 | list_add_tail(&page->lru, &pl->head); |
| 28 | if (pl->mapped_tail) | 36 | if (pl->mapped_tail) |
| 29 | kunmap(pl->mapped_tail); | 37 | ceph_pagelist_unmap_tail(pl); |
| 30 | pl->mapped_tail = kmap(page); | 38 | pl->mapped_tail = kmap(page); |
| 31 | return 0; | 39 | return 0; |
| 32 | } | 40 | } |
diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index 4868b9dcac5a..190b6c4a6f2b 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c | |||
| @@ -119,6 +119,7 @@ static struct ceph_snap_realm *ceph_create_snap_realm( | |||
| 119 | INIT_LIST_HEAD(&realm->children); | 119 | INIT_LIST_HEAD(&realm->children); |
| 120 | INIT_LIST_HEAD(&realm->child_item); | 120 | INIT_LIST_HEAD(&realm->child_item); |
| 121 | INIT_LIST_HEAD(&realm->empty_item); | 121 | INIT_LIST_HEAD(&realm->empty_item); |
| 122 | INIT_LIST_HEAD(&realm->dirty_item); | ||
| 122 | INIT_LIST_HEAD(&realm->inodes_with_caps); | 123 | INIT_LIST_HEAD(&realm->inodes_with_caps); |
| 123 | spin_lock_init(&realm->inodes_with_caps_lock); | 124 | spin_lock_init(&realm->inodes_with_caps_lock); |
| 124 | __insert_snap_realm(&mdsc->snap_realms, realm); | 125 | __insert_snap_realm(&mdsc->snap_realms, realm); |
| @@ -467,7 +468,7 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci) | |||
| 467 | INIT_LIST_HEAD(&capsnap->ci_item); | 468 | INIT_LIST_HEAD(&capsnap->ci_item); |
| 468 | INIT_LIST_HEAD(&capsnap->flushing_item); | 469 | INIT_LIST_HEAD(&capsnap->flushing_item); |
| 469 | 470 | ||
| 470 | capsnap->follows = snapc->seq - 1; | 471 | capsnap->follows = snapc->seq; |
| 471 | capsnap->issued = __ceph_caps_issued(ci, NULL); | 472 | capsnap->issued = __ceph_caps_issued(ci, NULL); |
| 472 | capsnap->dirty = dirty; | 473 | capsnap->dirty = dirty; |
| 473 | 474 | ||
| @@ -604,6 +605,7 @@ int ceph_update_snap_trace(struct ceph_mds_client *mdsc, | |||
| 604 | struct ceph_snap_realm *realm; | 605 | struct ceph_snap_realm *realm; |
| 605 | int invalidate = 0; | 606 | int invalidate = 0; |
| 606 | int err = -ENOMEM; | 607 | int err = -ENOMEM; |
| 608 | LIST_HEAD(dirty_realms); | ||
| 607 | 609 | ||
| 608 | dout("update_snap_trace deletion=%d\n", deletion); | 610 | dout("update_snap_trace deletion=%d\n", deletion); |
| 609 | more: | 611 | more: |
| @@ -626,24 +628,6 @@ more: | |||
| 626 | } | 628 | } |
| 627 | } | 629 | } |
| 628 | 630 | ||
| 629 | if (le64_to_cpu(ri->seq) > realm->seq) { | ||
| 630 | dout("update_snap_trace updating %llx %p %lld -> %lld\n", | ||
| 631 | realm->ino, realm, realm->seq, le64_to_cpu(ri->seq)); | ||
| 632 | /* | ||
| 633 | * if the realm seq has changed, queue a cap_snap for every | ||
| 634 | * inode with open caps. we do this _before_ we update | ||
| 635 | * the realm info so that we prepare for writeback under the | ||
| 636 | * _previous_ snap context. | ||
| 637 | * | ||
| 638 | * ...unless it's a snap deletion! | ||
| 639 | */ | ||
| 640 | if (!deletion) | ||
| 641 | queue_realm_cap_snaps(realm); | ||
| 642 | } else { | ||
| 643 | dout("update_snap_trace %llx %p seq %lld unchanged\n", | ||
| 644 | realm->ino, realm, realm->seq); | ||
| 645 | } | ||
| 646 | |||
| 647 | /* ensure the parent is correct */ | 631 | /* ensure the parent is correct */ |
| 648 | err = adjust_snap_realm_parent(mdsc, realm, le64_to_cpu(ri->parent)); | 632 | err = adjust_snap_realm_parent(mdsc, realm, le64_to_cpu(ri->parent)); |
| 649 | if (err < 0) | 633 | if (err < 0) |
| @@ -651,6 +635,8 @@ more: | |||
| 651 | invalidate += err; | 635 | invalidate += err; |
| 652 | 636 | ||
| 653 | if (le64_to_cpu(ri->seq) > realm->seq) { | 637 | if (le64_to_cpu(ri->seq) > realm->seq) { |
| 638 | dout("update_snap_trace updating %llx %p %lld -> %lld\n", | ||
| 639 | realm->ino, realm, realm->seq, le64_to_cpu(ri->seq)); | ||
| 654 | /* update realm parameters, snap lists */ | 640 | /* update realm parameters, snap lists */ |
| 655 | realm->seq = le64_to_cpu(ri->seq); | 641 | realm->seq = le64_to_cpu(ri->seq); |
| 656 | realm->created = le64_to_cpu(ri->created); | 642 | realm->created = le64_to_cpu(ri->created); |
| @@ -668,9 +654,17 @@ more: | |||
| 668 | if (err < 0) | 654 | if (err < 0) |
| 669 | goto fail; | 655 | goto fail; |
| 670 | 656 | ||
| 657 | /* queue realm for cap_snap creation */ | ||
| 658 | list_add(&realm->dirty_item, &dirty_realms); | ||
| 659 | |||
| 671 | invalidate = 1; | 660 | invalidate = 1; |
| 672 | } else if (!realm->cached_context) { | 661 | } else if (!realm->cached_context) { |
| 662 | dout("update_snap_trace %llx %p seq %lld new\n", | ||
| 663 | realm->ino, realm, realm->seq); | ||
| 673 | invalidate = 1; | 664 | invalidate = 1; |
| 665 | } else { | ||
| 666 | dout("update_snap_trace %llx %p seq %lld unchanged\n", | ||
| 667 | realm->ino, realm, realm->seq); | ||
| 674 | } | 668 | } |
| 675 | 669 | ||
| 676 | dout("done with %llx %p, invalidated=%d, %p %p\n", realm->ino, | 670 | dout("done with %llx %p, invalidated=%d, %p %p\n", realm->ino, |
| @@ -683,6 +677,14 @@ more: | |||
| 683 | if (invalidate) | 677 | if (invalidate) |
| 684 | rebuild_snap_realms(realm); | 678 | rebuild_snap_realms(realm); |
| 685 | 679 | ||
| 680 | /* | ||
| 681 | * queue cap snaps _after_ we've built the new snap contexts, | ||
| 682 | * so that i_head_snapc can be set appropriately. | ||
| 683 | */ | ||
| 684 | list_for_each_entry(realm, &dirty_realms, dirty_item) { | ||
| 685 | queue_realm_cap_snaps(realm); | ||
| 686 | } | ||
| 687 | |||
| 686 | __cleanup_empty_realms(mdsc); | 688 | __cleanup_empty_realms(mdsc); |
| 687 | return 0; | 689 | return 0; |
| 688 | 690 | ||
| @@ -715,7 +717,7 @@ static void flush_snaps(struct ceph_mds_client *mdsc) | |||
| 715 | igrab(inode); | 717 | igrab(inode); |
| 716 | spin_unlock(&mdsc->snap_flush_lock); | 718 | spin_unlock(&mdsc->snap_flush_lock); |
| 717 | spin_lock(&inode->i_lock); | 719 | spin_lock(&inode->i_lock); |
| 718 | __ceph_flush_snaps(ci, &session); | 720 | __ceph_flush_snaps(ci, &session, 0); |
| 719 | spin_unlock(&inode->i_lock); | 721 | spin_unlock(&inode->i_lock); |
| 720 | iput(inode); | 722 | iput(inode); |
| 721 | spin_lock(&mdsc->snap_flush_lock); | 723 | spin_lock(&mdsc->snap_flush_lock); |
| @@ -816,6 +818,7 @@ void ceph_handle_snap(struct ceph_mds_client *mdsc, | |||
| 816 | }; | 818 | }; |
| 817 | struct inode *inode = ceph_find_inode(sb, vino); | 819 | struct inode *inode = ceph_find_inode(sb, vino); |
| 818 | struct ceph_inode_info *ci; | 820 | struct ceph_inode_info *ci; |
| 821 | struct ceph_snap_realm *oldrealm; | ||
| 819 | 822 | ||
| 820 | if (!inode) | 823 | if (!inode) |
| 821 | continue; | 824 | continue; |
| @@ -841,18 +844,19 @@ void ceph_handle_snap(struct ceph_mds_client *mdsc, | |||
| 841 | dout(" will move %p to split realm %llx %p\n", | 844 | dout(" will move %p to split realm %llx %p\n", |
| 842 | inode, realm->ino, realm); | 845 | inode, realm->ino, realm); |
| 843 | /* | 846 | /* |
| 844 | * Remove the inode from the realm's inode | 847 | * Move the inode to the new realm |
| 845 | * list, but don't add it to the new realm | ||
| 846 | * yet. We don't want the cap_snap to be | ||
| 847 | * queued (again) by ceph_update_snap_trace() | ||
| 848 | * below. Queue it _now_, under the old context. | ||
| 849 | */ | 848 | */ |
| 850 | spin_lock(&realm->inodes_with_caps_lock); | 849 | spin_lock(&realm->inodes_with_caps_lock); |
| 851 | list_del_init(&ci->i_snap_realm_item); | 850 | list_del_init(&ci->i_snap_realm_item); |
| 851 | list_add(&ci->i_snap_realm_item, | ||
| 852 | &realm->inodes_with_caps); | ||
| 853 | oldrealm = ci->i_snap_realm; | ||
| 854 | ci->i_snap_realm = realm; | ||
| 852 | spin_unlock(&realm->inodes_with_caps_lock); | 855 | spin_unlock(&realm->inodes_with_caps_lock); |
| 853 | spin_unlock(&inode->i_lock); | 856 | spin_unlock(&inode->i_lock); |
| 854 | 857 | ||
| 855 | ceph_queue_cap_snap(ci); | 858 | ceph_get_snap_realm(mdsc, realm); |
| 859 | ceph_put_snap_realm(mdsc, oldrealm); | ||
| 856 | 860 | ||
| 857 | iput(inode); | 861 | iput(inode); |
| 858 | continue; | 862 | continue; |
| @@ -880,43 +884,9 @@ skip_inode: | |||
| 880 | ceph_update_snap_trace(mdsc, p, e, | 884 | ceph_update_snap_trace(mdsc, p, e, |
| 881 | op == CEPH_SNAP_OP_DESTROY); | 885 | op == CEPH_SNAP_OP_DESTROY); |
| 882 | 886 | ||
| 883 | if (op == CEPH_SNAP_OP_SPLIT) { | 887 | if (op == CEPH_SNAP_OP_SPLIT) |
| 884 | /* | ||
| 885 | * ok, _now_ add the inodes into the new realm. | ||
| 886 | */ | ||
| 887 | for (i = 0; i < num_split_inos; i++) { | ||
| 888 | struct ceph_vino vino = { | ||
| 889 | .ino = le64_to_cpu(split_inos[i]), | ||
| 890 | .snap = CEPH_NOSNAP, | ||
| 891 | }; | ||
| 892 | struct inode *inode = ceph_find_inode(sb, vino); | ||
| 893 | struct ceph_inode_info *ci; | ||
| 894 | |||
| 895 | if (!inode) | ||
| 896 | continue; | ||
| 897 | ci = ceph_inode(inode); | ||
| 898 | spin_lock(&inode->i_lock); | ||
| 899 | if (list_empty(&ci->i_snap_realm_item)) { | ||
| 900 | struct ceph_snap_realm *oldrealm = | ||
| 901 | ci->i_snap_realm; | ||
| 902 | |||
| 903 | dout(" moving %p to split realm %llx %p\n", | ||
| 904 | inode, realm->ino, realm); | ||
| 905 | spin_lock(&realm->inodes_with_caps_lock); | ||
| 906 | list_add(&ci->i_snap_realm_item, | ||
| 907 | &realm->inodes_with_caps); | ||
| 908 | ci->i_snap_realm = realm; | ||
| 909 | spin_unlock(&realm->inodes_with_caps_lock); | ||
| 910 | ceph_get_snap_realm(mdsc, realm); | ||
| 911 | ceph_put_snap_realm(mdsc, oldrealm); | ||
| 912 | } | ||
| 913 | spin_unlock(&inode->i_lock); | ||
| 914 | iput(inode); | ||
| 915 | } | ||
| 916 | |||
| 917 | /* we took a reference when we created the realm, above */ | 888 | /* we took a reference when we created the realm, above */ |
| 918 | ceph_put_snap_realm(mdsc, realm); | 889 | ceph_put_snap_realm(mdsc, realm); |
| 919 | } | ||
| 920 | 890 | ||
| 921 | __cleanup_empty_realms(mdsc); | 891 | __cleanup_empty_realms(mdsc); |
| 922 | 892 | ||
diff --git a/fs/ceph/super.h b/fs/ceph/super.h index c33897ae5725..b87638e84c4b 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h | |||
| @@ -690,6 +690,8 @@ struct ceph_snap_realm { | |||
| 690 | 690 | ||
| 691 | struct list_head empty_item; /* if i have ref==0 */ | 691 | struct list_head empty_item; /* if i have ref==0 */ |
| 692 | 692 | ||
| 693 | struct list_head dirty_item; /* if realm needs new context */ | ||
| 694 | |||
| 693 | /* the current set of snaps for this realm */ | 695 | /* the current set of snaps for this realm */ |
| 694 | struct ceph_snap_context *cached_context; | 696 | struct ceph_snap_context *cached_context; |
| 695 | 697 | ||
| @@ -826,7 +828,8 @@ extern void ceph_put_cap_refs(struct ceph_inode_info *ci, int had); | |||
| 826 | extern void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr, | 828 | extern void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr, |
| 827 | struct ceph_snap_context *snapc); | 829 | struct ceph_snap_context *snapc); |
| 828 | extern void __ceph_flush_snaps(struct ceph_inode_info *ci, | 830 | extern void __ceph_flush_snaps(struct ceph_inode_info *ci, |
| 829 | struct ceph_mds_session **psession); | 831 | struct ceph_mds_session **psession, |
| 832 | int again); | ||
| 830 | extern void ceph_check_caps(struct ceph_inode_info *ci, int flags, | 833 | extern void ceph_check_caps(struct ceph_inode_info *ci, int flags, |
| 831 | struct ceph_mds_session *session); | 834 | struct ceph_mds_session *session); |
| 832 | extern void ceph_check_delayed_caps(struct ceph_mds_client *mdsc); | 835 | extern void ceph_check_delayed_caps(struct ceph_mds_client *mdsc); |
diff --git a/fs/char_dev.c b/fs/char_dev.c index f80a4f25123c..143d393881cb 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c | |||
| @@ -40,7 +40,9 @@ struct backing_dev_info directly_mappable_cdev_bdi = { | |||
| 40 | #endif | 40 | #endif |
| 41 | /* permit direct mmap, for read, write or exec */ | 41 | /* permit direct mmap, for read, write or exec */ |
| 42 | BDI_CAP_MAP_DIRECT | | 42 | BDI_CAP_MAP_DIRECT | |
| 43 | BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP), | 43 | BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP | |
| 44 | /* no writeback happens */ | ||
| 45 | BDI_CAP_NO_ACCT_AND_WRITEBACK), | ||
| 44 | }; | 46 | }; |
| 45 | 47 | ||
| 46 | static struct kobj_map *cdev_map; | 48 | static struct kobj_map *cdev_map; |
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 0da1debd499d..917b7d449bb2 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig | |||
| @@ -2,8 +2,6 @@ config CIFS | |||
| 2 | tristate "CIFS support (advanced network filesystem, SMBFS successor)" | 2 | tristate "CIFS support (advanced network filesystem, SMBFS successor)" |
| 3 | depends on INET | 3 | depends on INET |
| 4 | select NLS | 4 | select NLS |
| 5 | select CRYPTO_MD5 | ||
| 6 | select CRYPTO_ARC4 | ||
| 7 | help | 5 | help |
| 8 | This is the client VFS module for the Common Internet File System | 6 | This is the client VFS module for the Common Internet File System |
| 9 | (CIFS) protocol which is the successor to the Server Message Block | 7 | (CIFS) protocol which is the successor to the Server Message Block |
diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index 21f0fbd86989..cfd1ce34e0bc 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c | |||
| @@ -597,13 +597,13 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
| 597 | if (compare_oid(oid, oidlen, MSKRB5_OID, | 597 | if (compare_oid(oid, oidlen, MSKRB5_OID, |
| 598 | MSKRB5_OID_LEN)) | 598 | MSKRB5_OID_LEN)) |
| 599 | server->sec_mskerberos = true; | 599 | server->sec_mskerberos = true; |
| 600 | if (compare_oid(oid, oidlen, KRB5U2U_OID, | 600 | else if (compare_oid(oid, oidlen, KRB5U2U_OID, |
| 601 | KRB5U2U_OID_LEN)) | 601 | KRB5U2U_OID_LEN)) |
| 602 | server->sec_kerberosu2u = true; | 602 | server->sec_kerberosu2u = true; |
| 603 | if (compare_oid(oid, oidlen, KRB5_OID, | 603 | else if (compare_oid(oid, oidlen, KRB5_OID, |
| 604 | KRB5_OID_LEN)) | 604 | KRB5_OID_LEN)) |
| 605 | server->sec_kerberos = true; | 605 | server->sec_kerberos = true; |
| 606 | if (compare_oid(oid, oidlen, NTLMSSP_OID, | 606 | else if (compare_oid(oid, oidlen, NTLMSSP_OID, |
| 607 | NTLMSSP_OID_LEN)) | 607 | NTLMSSP_OID_LEN)) |
| 608 | server->sec_ntlmssp = true; | 608 | server->sec_ntlmssp = true; |
| 609 | 609 | ||
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 709f2296bdb4..35042d8f7338 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
| @@ -27,7 +27,6 @@ | |||
| 27 | #include "md5.h" | 27 | #include "md5.h" |
| 28 | #include "cifs_unicode.h" | 28 | #include "cifs_unicode.h" |
| 29 | #include "cifsproto.h" | 29 | #include "cifsproto.h" |
| 30 | #include "ntlmssp.h" | ||
| 31 | #include <linux/ctype.h> | 30 | #include <linux/ctype.h> |
| 32 | #include <linux/random.h> | 31 | #include <linux/random.h> |
| 33 | 32 | ||
| @@ -43,43 +42,21 @@ extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8, | |||
| 43 | unsigned char *p24); | 42 | unsigned char *p24); |
| 44 | 43 | ||
| 45 | static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, | 44 | static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, |
| 46 | struct TCP_Server_Info *server, char *signature) | 45 | const struct mac_key *key, char *signature) |
| 47 | { | 46 | { |
| 48 | int rc; | 47 | struct MD5Context context; |
| 49 | 48 | ||
| 50 | if (cifs_pdu == NULL || server == NULL || signature == NULL) | 49 | if ((cifs_pdu == NULL) || (signature == NULL) || (key == NULL)) |
| 51 | return -EINVAL; | 50 | return -EINVAL; |
| 52 | 51 | ||
| 53 | if (!server->ntlmssp.sdescmd5) { | 52 | cifs_MD5_init(&context); |
| 54 | cERROR(1, | 53 | cifs_MD5_update(&context, (char *)&key->data, key->len); |
| 55 | "cifs_calculate_signature: can't generate signature\n"); | 54 | cifs_MD5_update(&context, cifs_pdu->Protocol, cifs_pdu->smb_buf_length); |
| 56 | return -1; | ||
| 57 | } | ||
| 58 | |||
| 59 | rc = crypto_shash_init(&server->ntlmssp.sdescmd5->shash); | ||
| 60 | if (rc) { | ||
| 61 | cERROR(1, "cifs_calculate_signature: oould not init md5\n"); | ||
| 62 | return rc; | ||
| 63 | } | ||
| 64 | |||
| 65 | if (server->secType == RawNTLMSSP) | ||
| 66 | crypto_shash_update(&server->ntlmssp.sdescmd5->shash, | ||
| 67 | server->session_key.data.ntlmv2.key, | ||
| 68 | CIFS_NTLMV2_SESSKEY_SIZE); | ||
| 69 | else | ||
| 70 | crypto_shash_update(&server->ntlmssp.sdescmd5->shash, | ||
| 71 | (char *)&server->session_key.data, | ||
| 72 | server->session_key.len); | ||
| 73 | |||
| 74 | crypto_shash_update(&server->ntlmssp.sdescmd5->shash, | ||
| 75 | cifs_pdu->Protocol, cifs_pdu->smb_buf_length); | ||
| 76 | 55 | ||
| 77 | rc = crypto_shash_final(&server->ntlmssp.sdescmd5->shash, signature); | 56 | cifs_MD5_final(signature, &context); |
| 78 | 57 | return 0; | |
| 79 | return rc; | ||
| 80 | } | 58 | } |
| 81 | 59 | ||
| 82 | |||
| 83 | int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, | 60 | int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, |
| 84 | __u32 *pexpected_response_sequence_number) | 61 | __u32 *pexpected_response_sequence_number) |
| 85 | { | 62 | { |
| @@ -101,7 +78,8 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, | |||
| 101 | server->sequence_number++; | 78 | server->sequence_number++; |
| 102 | spin_unlock(&GlobalMid_Lock); | 79 | spin_unlock(&GlobalMid_Lock); |
| 103 | 80 | ||
| 104 | rc = cifs_calculate_signature(cifs_pdu, server, smb_signature); | 81 | rc = cifs_calculate_signature(cifs_pdu, &server->mac_signing_key, |
| 82 | smb_signature); | ||
| 105 | if (rc) | 83 | if (rc) |
| 106 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); | 84 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); |
| 107 | else | 85 | else |
| @@ -111,39 +89,21 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, | |||
| 111 | } | 89 | } |
| 112 | 90 | ||
| 113 | static int cifs_calc_signature2(const struct kvec *iov, int n_vec, | 91 | static int cifs_calc_signature2(const struct kvec *iov, int n_vec, |
| 114 | struct TCP_Server_Info *server, char *signature) | 92 | const struct mac_key *key, char *signature) |
| 115 | { | 93 | { |
| 94 | struct MD5Context context; | ||
| 116 | int i; | 95 | int i; |
| 117 | int rc; | ||
| 118 | 96 | ||
| 119 | if (iov == NULL || server == NULL || signature == NULL) | 97 | if ((iov == NULL) || (signature == NULL) || (key == NULL)) |
| 120 | return -EINVAL; | 98 | return -EINVAL; |
| 121 | 99 | ||
| 122 | if (!server->ntlmssp.sdescmd5) { | 100 | cifs_MD5_init(&context); |
| 123 | cERROR(1, "cifs_calc_signature2: can't generate signature\n"); | 101 | cifs_MD5_update(&context, (char *)&key->data, key->len); |
| 124 | return -1; | ||
| 125 | } | ||
| 126 | |||
| 127 | rc = crypto_shash_init(&server->ntlmssp.sdescmd5->shash); | ||
| 128 | if (rc) { | ||
| 129 | cERROR(1, "cifs_calc_signature2: oould not init md5\n"); | ||
| 130 | return rc; | ||
| 131 | } | ||
| 132 | |||
| 133 | if (server->secType == RawNTLMSSP) | ||
| 134 | crypto_shash_update(&server->ntlmssp.sdescmd5->shash, | ||
| 135 | server->session_key.data.ntlmv2.key, | ||
| 136 | CIFS_NTLMV2_SESSKEY_SIZE); | ||
| 137 | else | ||
| 138 | crypto_shash_update(&server->ntlmssp.sdescmd5->shash, | ||
| 139 | (char *)&server->session_key.data, | ||
| 140 | server->session_key.len); | ||
| 141 | |||
| 142 | for (i = 0; i < n_vec; i++) { | 102 | for (i = 0; i < n_vec; i++) { |
| 143 | if (iov[i].iov_len == 0) | 103 | if (iov[i].iov_len == 0) |
| 144 | continue; | 104 | continue; |
| 145 | if (iov[i].iov_base == NULL) { | 105 | if (iov[i].iov_base == NULL) { |
| 146 | cERROR(1, "cifs_calc_signature2: null iovec entry"); | 106 | cERROR(1, "null iovec entry"); |
| 147 | return -EIO; | 107 | return -EIO; |
| 148 | } | 108 | } |
| 149 | /* The first entry includes a length field (which does not get | 109 | /* The first entry includes a length field (which does not get |
| @@ -151,18 +111,18 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec, | |||
| 151 | if (i == 0) { | 111 | if (i == 0) { |
| 152 | if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ | 112 | if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ |
| 153 | break; /* nothing to sign or corrupt header */ | 113 | break; /* nothing to sign or corrupt header */ |
| 154 | crypto_shash_update(&server->ntlmssp.sdescmd5->shash, | 114 | cifs_MD5_update(&context, iov[0].iov_base+4, |
| 155 | iov[i].iov_base + 4, iov[i].iov_len - 4); | 115 | iov[0].iov_len-4); |
| 156 | } else | 116 | } else |
| 157 | crypto_shash_update(&server->ntlmssp.sdescmd5->shash, | 117 | cifs_MD5_update(&context, iov[i].iov_base, iov[i].iov_len); |
| 158 | iov[i].iov_base, iov[i].iov_len); | ||
| 159 | } | 118 | } |
| 160 | 119 | ||
| 161 | rc = crypto_shash_final(&server->ntlmssp.sdescmd5->shash, signature); | 120 | cifs_MD5_final(signature, &context); |
| 162 | 121 | ||
| 163 | return rc; | 122 | return 0; |
| 164 | } | 123 | } |
| 165 | 124 | ||
| 125 | |||
| 166 | int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, | 126 | int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, |
| 167 | __u32 *pexpected_response_sequence_number) | 127 | __u32 *pexpected_response_sequence_number) |
| 168 | { | 128 | { |
| @@ -185,7 +145,8 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, | |||
| 185 | server->sequence_number++; | 145 | server->sequence_number++; |
| 186 | spin_unlock(&GlobalMid_Lock); | 146 | spin_unlock(&GlobalMid_Lock); |
| 187 | 147 | ||
| 188 | rc = cifs_calc_signature2(iov, n_vec, server, smb_signature); | 148 | rc = cifs_calc_signature2(iov, n_vec, &server->mac_signing_key, |
| 149 | smb_signature); | ||
| 189 | if (rc) | 150 | if (rc) |
| 190 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); | 151 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); |
| 191 | else | 152 | else |
| @@ -195,14 +156,14 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, | |||
| 195 | } | 156 | } |
| 196 | 157 | ||
| 197 | int cifs_verify_signature(struct smb_hdr *cifs_pdu, | 158 | int cifs_verify_signature(struct smb_hdr *cifs_pdu, |
| 198 | struct TCP_Server_Info *server, | 159 | const struct mac_key *mac_key, |
| 199 | __u32 expected_sequence_number) | 160 | __u32 expected_sequence_number) |
| 200 | { | 161 | { |
| 201 | int rc; | 162 | unsigned int rc; |
| 202 | char server_response_sig[8]; | 163 | char server_response_sig[8]; |
| 203 | char what_we_think_sig_should_be[20]; | 164 | char what_we_think_sig_should_be[20]; |
| 204 | 165 | ||
| 205 | if (cifs_pdu == NULL || server == NULL) | 166 | if ((cifs_pdu == NULL) || (mac_key == NULL)) |
| 206 | return -EINVAL; | 167 | return -EINVAL; |
| 207 | 168 | ||
| 208 | if (cifs_pdu->Command == SMB_COM_NEGOTIATE) | 169 | if (cifs_pdu->Command == SMB_COM_NEGOTIATE) |
| @@ -231,7 +192,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, | |||
| 231 | cpu_to_le32(expected_sequence_number); | 192 | cpu_to_le32(expected_sequence_number); |
| 232 | cifs_pdu->Signature.Sequence.Reserved = 0; | 193 | cifs_pdu->Signature.Sequence.Reserved = 0; |
| 233 | 194 | ||
| 234 | rc = cifs_calculate_signature(cifs_pdu, server, | 195 | rc = cifs_calculate_signature(cifs_pdu, mac_key, |
| 235 | what_we_think_sig_should_be); | 196 | what_we_think_sig_should_be); |
| 236 | 197 | ||
| 237 | if (rc) | 198 | if (rc) |
| @@ -248,7 +209,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, | |||
| 248 | } | 209 | } |
| 249 | 210 | ||
| 250 | /* We fill in key by putting in 40 byte array which was allocated by caller */ | 211 | /* We fill in key by putting in 40 byte array which was allocated by caller */ |
| 251 | int cifs_calculate_session_key(struct session_key *key, const char *rn, | 212 | int cifs_calculate_mac_key(struct mac_key *key, const char *rn, |
| 252 | const char *password) | 213 | const char *password) |
| 253 | { | 214 | { |
| 254 | char temp_key[16]; | 215 | char temp_key[16]; |
| @@ -306,52 +267,38 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, | |||
| 306 | { | 267 | { |
| 307 | int rc = 0; | 268 | int rc = 0; |
| 308 | int len; | 269 | int len; |
| 309 | char nt_hash[CIFS_NTHASH_SIZE]; | 270 | char nt_hash[16]; |
| 271 | struct HMACMD5Context *pctxt; | ||
| 310 | wchar_t *user; | 272 | wchar_t *user; |
| 311 | wchar_t *domain; | 273 | wchar_t *domain; |
| 312 | wchar_t *server; | ||
| 313 | 274 | ||
| 314 | if (!ses->server->ntlmssp.sdeschmacmd5) { | 275 | pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL); |
| 315 | cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); | 276 | |
| 316 | return -1; | 277 | if (pctxt == NULL) |
| 317 | } | 278 | return -ENOMEM; |
| 318 | 279 | ||
| 319 | /* calculate md4 hash of password */ | 280 | /* calculate md4 hash of password */ |
| 320 | E_md4hash(ses->password, nt_hash); | 281 | E_md4hash(ses->password, nt_hash); |
| 321 | 282 | ||
| 322 | crypto_shash_setkey(ses->server->ntlmssp.hmacmd5, nt_hash, | 283 | /* convert Domainname to unicode and uppercase */ |
| 323 | CIFS_NTHASH_SIZE); | 284 | hmac_md5_init_limK_to_64(nt_hash, 16, pctxt); |
| 324 | |||
| 325 | rc = crypto_shash_init(&ses->server->ntlmssp.sdeschmacmd5->shash); | ||
| 326 | if (rc) { | ||
| 327 | cERROR(1, "calc_ntlmv2_hash: could not init hmacmd5\n"); | ||
| 328 | return rc; | ||
| 329 | } | ||
| 330 | 285 | ||
| 331 | /* convert ses->userName to unicode and uppercase */ | 286 | /* convert ses->userName to unicode and uppercase */ |
| 332 | len = strlen(ses->userName); | 287 | len = strlen(ses->userName); |
| 333 | user = kmalloc(2 + (len * 2), GFP_KERNEL); | 288 | user = kmalloc(2 + (len * 2), GFP_KERNEL); |
| 334 | if (user == NULL) { | 289 | if (user == NULL) |
| 335 | cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n"); | ||
| 336 | rc = -ENOMEM; | ||
| 337 | goto calc_exit_2; | 290 | goto calc_exit_2; |
| 338 | } | ||
| 339 | len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); | 291 | len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); |
| 340 | UniStrupr(user); | 292 | UniStrupr(user); |
| 341 | 293 | hmac_md5_update((char *)user, 2*len, pctxt); | |
| 342 | crypto_shash_update(&ses->server->ntlmssp.sdeschmacmd5->shash, | ||
| 343 | (char *)user, 2 * len); | ||
| 344 | 294 | ||
| 345 | /* convert ses->domainName to unicode and uppercase */ | 295 | /* convert ses->domainName to unicode and uppercase */ |
| 346 | if (ses->domainName) { | 296 | if (ses->domainName) { |
| 347 | len = strlen(ses->domainName); | 297 | len = strlen(ses->domainName); |
| 348 | 298 | ||
| 349 | domain = kmalloc(2 + (len * 2), GFP_KERNEL); | 299 | domain = kmalloc(2 + (len * 2), GFP_KERNEL); |
| 350 | if (domain == NULL) { | 300 | if (domain == NULL) |
| 351 | cERROR(1, "calc_ntlmv2_hash: domain mem alloc failure"); | ||
| 352 | rc = -ENOMEM; | ||
| 353 | goto calc_exit_1; | 301 | goto calc_exit_1; |
| 354 | } | ||
| 355 | len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len, | 302 | len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len, |
| 356 | nls_cp); | 303 | nls_cp); |
| 357 | /* the following line was removed since it didn't work well | 304 | /* the following line was removed since it didn't work well |
| @@ -359,292 +306,65 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, | |||
| 359 | Maybe converting the domain name earlier makes sense */ | 306 | Maybe converting the domain name earlier makes sense */ |
| 360 | /* UniStrupr(domain); */ | 307 | /* UniStrupr(domain); */ |
| 361 | 308 | ||
| 362 | crypto_shash_update(&ses->server->ntlmssp.sdeschmacmd5->shash, | 309 | hmac_md5_update((char *)domain, 2*len, pctxt); |
| 363 | (char *)domain, 2 * len); | ||
| 364 | 310 | ||
| 365 | kfree(domain); | 311 | kfree(domain); |
| 366 | } else if (ses->serverName) { | ||
| 367 | len = strlen(ses->serverName); | ||
| 368 | |||
| 369 | server = kmalloc(2 + (len * 2), GFP_KERNEL); | ||
| 370 | if (server == NULL) { | ||
| 371 | cERROR(1, "calc_ntlmv2_hash: server mem alloc failure"); | ||
| 372 | rc = -ENOMEM; | ||
| 373 | goto calc_exit_1; | ||
| 374 | } | ||
| 375 | len = cifs_strtoUCS((__le16 *)server, ses->serverName, len, | ||
| 376 | nls_cp); | ||
| 377 | /* the following line was removed since it didn't work well | ||
| 378 | with lower cased domain name that passed as an option. | ||
| 379 | Maybe converting the domain name earlier makes sense */ | ||
| 380 | /* UniStrupr(domain); */ | ||
| 381 | |||
| 382 | crypto_shash_update(&ses->server->ntlmssp.sdeschmacmd5->shash, | ||
| 383 | (char *)server, 2 * len); | ||
| 384 | |||
| 385 | kfree(server); | ||
| 386 | } | 312 | } |
| 387 | |||
| 388 | rc = crypto_shash_final(&ses->server->ntlmssp.sdeschmacmd5->shash, | ||
| 389 | ses->server->ntlmv2_hash); | ||
| 390 | |||
| 391 | calc_exit_1: | 313 | calc_exit_1: |
| 392 | kfree(user); | 314 | kfree(user); |
| 393 | calc_exit_2: | 315 | calc_exit_2: |
| 394 | /* BB FIXME what about bytes 24 through 40 of the signing key? | 316 | /* BB FIXME what about bytes 24 through 40 of the signing key? |
| 395 | compare with the NTLM example */ | 317 | compare with the NTLM example */ |
| 318 | hmac_md5_final(ses->server->ntlmv2_hash, pctxt); | ||
| 396 | 319 | ||
| 320 | kfree(pctxt); | ||
| 397 | return rc; | 321 | return rc; |
| 398 | } | 322 | } |
| 399 | 323 | ||
| 400 | static int | 324 | void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, |
| 401 | find_domain_name(struct cifsSesInfo *ses) | ||
| 402 | { | ||
| 403 | int rc = 0; | ||
| 404 | unsigned int attrsize; | ||
| 405 | unsigned int type; | ||
| 406 | unsigned char *blobptr; | ||
| 407 | struct ntlmssp2_name *attrptr; | ||
| 408 | |||
| 409 | if (ses->server->tiblob) { | ||
| 410 | blobptr = ses->server->tiblob; | ||
| 411 | attrptr = (struct ntlmssp2_name *) blobptr; | ||
| 412 | |||
| 413 | while ((type = attrptr->type) != 0) { | ||
| 414 | blobptr += 2; /* advance attr type */ | ||
| 415 | attrsize = attrptr->length; | ||
| 416 | blobptr += 2; /* advance attr size */ | ||
| 417 | if (type == NTLMSSP_AV_NB_DOMAIN_NAME) { | ||
| 418 | if (!ses->domainName) { | ||
| 419 | ses->domainName = | ||
| 420 | kmalloc(attrptr->length + 1, | ||
| 421 | GFP_KERNEL); | ||
| 422 | if (!ses->domainName) | ||
| 423 | return -ENOMEM; | ||
| 424 | cifs_from_ucs2(ses->domainName, | ||
| 425 | (__le16 *)blobptr, | ||
| 426 | attrptr->length, | ||
| 427 | attrptr->length, | ||
| 428 | load_nls_default(), false); | ||
| 429 | } | ||
| 430 | } | ||
| 431 | blobptr += attrsize; /* advance attr value */ | ||
| 432 | attrptr = (struct ntlmssp2_name *) blobptr; | ||
| 433 | } | ||
| 434 | } else { | ||
| 435 | ses->server->tilen = 2 * sizeof(struct ntlmssp2_name); | ||
| 436 | ses->server->tiblob = kmalloc(ses->server->tilen, GFP_KERNEL); | ||
| 437 | if (!ses->server->tiblob) { | ||
| 438 | ses->server->tilen = 0; | ||
| 439 | cERROR(1, "Challenge target info allocation failure"); | ||
| 440 | return -ENOMEM; | ||
| 441 | } | ||
| 442 | memset(ses->server->tiblob, 0x0, ses->server->tilen); | ||
| 443 | attrptr = (struct ntlmssp2_name *) ses->server->tiblob; | ||
| 444 | attrptr->type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE); | ||
| 445 | } | ||
| 446 | |||
| 447 | return rc; | ||
| 448 | } | ||
| 449 | |||
| 450 | static int | ||
| 451 | CalcNTLMv2_response(const struct TCP_Server_Info *server, | ||
| 452 | char *v2_session_response) | ||
| 453 | { | ||
| 454 | int rc; | ||
| 455 | |||
| 456 | if (!server->ntlmssp.sdeschmacmd5) { | ||
| 457 | cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); | ||
| 458 | return -1; | ||
| 459 | } | ||
| 460 | |||
| 461 | crypto_shash_setkey(server->ntlmssp.hmacmd5, server->ntlmv2_hash, | ||
| 462 | CIFS_HMAC_MD5_HASH_SIZE); | ||
| 463 | |||
| 464 | rc = crypto_shash_init(&server->ntlmssp.sdeschmacmd5->shash); | ||
| 465 | if (rc) { | ||
| 466 | cERROR(1, "CalcNTLMv2_response: could not init hmacmd5"); | ||
| 467 | return rc; | ||
| 468 | } | ||
| 469 | |||
| 470 | memcpy(v2_session_response + CIFS_SERVER_CHALLENGE_SIZE, | ||
| 471 | server->cryptKey, CIFS_SERVER_CHALLENGE_SIZE); | ||
| 472 | crypto_shash_update(&server->ntlmssp.sdeschmacmd5->shash, | ||
| 473 | v2_session_response + CIFS_SERVER_CHALLENGE_SIZE, | ||
| 474 | sizeof(struct ntlmv2_resp) - CIFS_SERVER_CHALLENGE_SIZE); | ||
| 475 | |||
| 476 | if (server->tilen) | ||
| 477 | crypto_shash_update(&server->ntlmssp.sdeschmacmd5->shash, | ||
| 478 | server->tiblob, server->tilen); | ||
| 479 | |||
| 480 | rc = crypto_shash_final(&server->ntlmssp.sdeschmacmd5->shash, | ||
| 481 | v2_session_response); | ||
| 482 | |||
| 483 | return rc; | ||
| 484 | } | ||
| 485 | |||
| 486 | int | ||
| 487 | setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, | ||
| 488 | const struct nls_table *nls_cp) | 325 | const struct nls_table *nls_cp) |
| 489 | { | 326 | { |
| 490 | int rc = 0; | 327 | int rc; |
| 491 | struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf; | 328 | struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf; |
| 329 | struct HMACMD5Context context; | ||
| 492 | 330 | ||
| 493 | buf->blob_signature = cpu_to_le32(0x00000101); | 331 | buf->blob_signature = cpu_to_le32(0x00000101); |
| 494 | buf->reserved = 0; | 332 | buf->reserved = 0; |
| 495 | buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | 333 | buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); |
| 496 | get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); | 334 | get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); |
| 497 | buf->reserved2 = 0; | 335 | buf->reserved2 = 0; |
| 498 | 336 | buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE); | |
| 499 | if (!ses->domainName) { | 337 | buf->names[0].length = 0; |
| 500 | rc = find_domain_name(ses); | 338 | buf->names[1].type = 0; |
| 501 | if (rc) { | 339 | buf->names[1].length = 0; |
| 502 | cERROR(1, "could not get domain/server name rc %d", rc); | ||
| 503 | return rc; | ||
| 504 | } | ||
| 505 | } | ||
| 506 | 340 | ||
| 507 | /* calculate buf->ntlmv2_hash */ | 341 | /* calculate buf->ntlmv2_hash */ |
| 508 | rc = calc_ntlmv2_hash(ses, nls_cp); | 342 | rc = calc_ntlmv2_hash(ses, nls_cp); |
| 509 | if (rc) { | 343 | if (rc) |
| 510 | cERROR(1, "could not get v2 hash rc %d", rc); | ||
| 511 | return rc; | ||
| 512 | } | ||
| 513 | rc = CalcNTLMv2_response(ses->server, resp_buf); | ||
| 514 | if (rc) { | ||
| 515 | cERROR(1, "could not get v2 hash rc %d", rc); | 344 | cERROR(1, "could not get v2 hash rc %d", rc); |
| 516 | return rc; | 345 | CalcNTLMv2_response(ses, resp_buf); |
| 517 | } | ||
| 518 | |||
| 519 | if (!ses->server->ntlmssp.sdeschmacmd5) { | ||
| 520 | cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); | ||
| 521 | return -1; | ||
| 522 | } | ||
| 523 | |||
| 524 | crypto_shash_setkey(ses->server->ntlmssp.hmacmd5, | ||
| 525 | ses->server->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); | ||
| 526 | 346 | ||
| 527 | rc = crypto_shash_init(&ses->server->ntlmssp.sdeschmacmd5->shash); | 347 | /* now calculate the MAC key for NTLMv2 */ |
| 528 | if (rc) { | 348 | hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context); |
| 529 | cERROR(1, "setup_ntlmv2_rsp: could not init hmacmd5\n"); | 349 | hmac_md5_update(resp_buf, 16, &context); |
| 530 | return rc; | 350 | hmac_md5_final(ses->server->mac_signing_key.data.ntlmv2.key, &context); |
| 531 | } | ||
| 532 | 351 | ||
| 533 | crypto_shash_update(&ses->server->ntlmssp.sdeschmacmd5->shash, | 352 | memcpy(&ses->server->mac_signing_key.data.ntlmv2.resp, resp_buf, |
| 534 | resp_buf, CIFS_HMAC_MD5_HASH_SIZE); | 353 | sizeof(struct ntlmv2_resp)); |
| 535 | 354 | ses->server->mac_signing_key.len = 16 + sizeof(struct ntlmv2_resp); | |
| 536 | rc = crypto_shash_final(&ses->server->ntlmssp.sdeschmacmd5->shash, | ||
| 537 | ses->server->session_key.data.ntlmv2.key); | ||
| 538 | |||
| 539 | memcpy(&ses->server->session_key.data.ntlmv2.resp, resp_buf, | ||
| 540 | sizeof(struct ntlmv2_resp)); | ||
| 541 | ses->server->session_key.len = 16 + sizeof(struct ntlmv2_resp); | ||
| 542 | |||
| 543 | return rc; | ||
| 544 | } | 355 | } |
| 545 | 356 | ||
| 546 | int | 357 | void CalcNTLMv2_response(const struct cifsSesInfo *ses, |
| 547 | calc_seckey(struct TCP_Server_Info *server) | 358 | char *v2_session_response) |
| 548 | { | ||
| 549 | int rc; | ||
| 550 | unsigned char sec_key[CIFS_NTLMV2_SESSKEY_SIZE]; | ||
| 551 | struct crypto_blkcipher *tfm_arc4; | ||
| 552 | struct scatterlist sgin, sgout; | ||
| 553 | struct blkcipher_desc desc; | ||
| 554 | |||
| 555 | get_random_bytes(sec_key, CIFS_NTLMV2_SESSKEY_SIZE); | ||
| 556 | |||
| 557 | tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", | ||
| 558 | 0, CRYPTO_ALG_ASYNC); | ||
| 559 | if (!tfm_arc4 || IS_ERR(tfm_arc4)) { | ||
| 560 | cERROR(1, "could not allocate " "master crypto API arc4\n"); | ||
| 561 | return 1; | ||
| 562 | } | ||
| 563 | |||
| 564 | desc.tfm = tfm_arc4; | ||
| 565 | |||
| 566 | crypto_blkcipher_setkey(tfm_arc4, | ||
| 567 | server->session_key.data.ntlmv2.key, CIFS_CPHTXT_SIZE); | ||
| 568 | sg_init_one(&sgin, sec_key, CIFS_CPHTXT_SIZE); | ||
| 569 | sg_init_one(&sgout, server->ntlmssp.ciphertext, CIFS_CPHTXT_SIZE); | ||
| 570 | rc = crypto_blkcipher_encrypt(&desc, &sgout, &sgin, CIFS_CPHTXT_SIZE); | ||
| 571 | |||
| 572 | if (!rc) | ||
| 573 | memcpy(server->session_key.data.ntlmv2.key, | ||
| 574 | sec_key, CIFS_NTLMV2_SESSKEY_SIZE); | ||
| 575 | |||
| 576 | crypto_free_blkcipher(tfm_arc4); | ||
| 577 | |||
| 578 | return 0; | ||
| 579 | } | ||
| 580 | |||
| 581 | void | ||
| 582 | cifs_crypto_shash_release(struct TCP_Server_Info *server) | ||
| 583 | { | ||
| 584 | if (server->ntlmssp.md5) | ||
| 585 | crypto_free_shash(server->ntlmssp.md5); | ||
| 586 | |||
| 587 | if (server->ntlmssp.hmacmd5) | ||
| 588 | crypto_free_shash(server->ntlmssp.hmacmd5); | ||
| 589 | |||
| 590 | kfree(server->ntlmssp.sdeschmacmd5); | ||
| 591 | |||
| 592 | kfree(server->ntlmssp.sdescmd5); | ||
| 593 | } | ||
| 594 | |||
| 595 | int | ||
| 596 | cifs_crypto_shash_allocate(struct TCP_Server_Info *server) | ||
| 597 | { | 359 | { |
| 598 | int rc; | 360 | struct HMACMD5Context context; |
| 599 | unsigned int size; | 361 | /* rest of v2 struct already generated */ |
| 600 | 362 | memcpy(v2_session_response + 8, ses->server->cryptKey, 8); | |
| 601 | server->ntlmssp.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0); | 363 | hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context); |
| 602 | if (!server->ntlmssp.hmacmd5 || | ||
| 603 | IS_ERR(server->ntlmssp.hmacmd5)) { | ||
| 604 | cERROR(1, "could not allocate crypto hmacmd5\n"); | ||
| 605 | return 1; | ||
| 606 | } | ||
| 607 | |||
| 608 | server->ntlmssp.md5 = crypto_alloc_shash("md5", 0, 0); | ||
| 609 | if (!server->ntlmssp.md5 || IS_ERR(server->ntlmssp.md5)) { | ||
| 610 | cERROR(1, "could not allocate crypto md5\n"); | ||
| 611 | rc = 1; | ||
| 612 | goto cifs_crypto_shash_allocate_ret1; | ||
| 613 | } | ||
| 614 | |||
| 615 | size = sizeof(struct shash_desc) + | ||
| 616 | crypto_shash_descsize(server->ntlmssp.hmacmd5); | ||
| 617 | server->ntlmssp.sdeschmacmd5 = kmalloc(size, GFP_KERNEL); | ||
| 618 | if (!server->ntlmssp.sdeschmacmd5) { | ||
| 619 | cERROR(1, "cifs_crypto_shash_allocate: can't alloc hmacmd5\n"); | ||
| 620 | rc = -ENOMEM; | ||
| 621 | goto cifs_crypto_shash_allocate_ret2; | ||
| 622 | } | ||
| 623 | server->ntlmssp.sdeschmacmd5->shash.tfm = server->ntlmssp.hmacmd5; | ||
| 624 | server->ntlmssp.sdeschmacmd5->shash.flags = 0x0; | ||
| 625 | 364 | ||
| 365 | hmac_md5_update(v2_session_response+8, | ||
| 366 | sizeof(struct ntlmv2_resp) - 8, &context); | ||
| 626 | 367 | ||
| 627 | size = sizeof(struct shash_desc) + | 368 | hmac_md5_final(v2_session_response, &context); |
| 628 | crypto_shash_descsize(server->ntlmssp.md5); | 369 | /* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ |
| 629 | server->ntlmssp.sdescmd5 = kmalloc(size, GFP_KERNEL); | ||
| 630 | if (!server->ntlmssp.sdescmd5) { | ||
| 631 | cERROR(1, "cifs_crypto_shash_allocate: can't alloc md5\n"); | ||
| 632 | rc = -ENOMEM; | ||
| 633 | goto cifs_crypto_shash_allocate_ret3; | ||
| 634 | } | ||
| 635 | server->ntlmssp.sdescmd5->shash.tfm = server->ntlmssp.md5; | ||
| 636 | server->ntlmssp.sdescmd5->shash.flags = 0x0; | ||
| 637 | |||
| 638 | return 0; | ||
| 639 | |||
| 640 | cifs_crypto_shash_allocate_ret3: | ||
| 641 | kfree(server->ntlmssp.sdeschmacmd5); | ||
| 642 | |||
| 643 | cifs_crypto_shash_allocate_ret2: | ||
| 644 | crypto_free_shash(server->ntlmssp.md5); | ||
| 645 | |||
| 646 | cifs_crypto_shash_allocate_ret1: | ||
| 647 | crypto_free_shash(server->ntlmssp.hmacmd5); | ||
| 648 | |||
| 649 | return rc; | ||
| 650 | } | 370 | } |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index c9d0cfc086eb..0cdfb8c32ac6 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -25,9 +25,6 @@ | |||
| 25 | #include <linux/workqueue.h> | 25 | #include <linux/workqueue.h> |
| 26 | #include "cifs_fs_sb.h" | 26 | #include "cifs_fs_sb.h" |
| 27 | #include "cifsacl.h" | 27 | #include "cifsacl.h" |
| 28 | #include <crypto/internal/hash.h> | ||
| 29 | #include <linux/scatterlist.h> | ||
| 30 | |||
| 31 | /* | 28 | /* |
| 32 | * The sizes of various internal tables and strings | 29 | * The sizes of various internal tables and strings |
| 33 | */ | 30 | */ |
| @@ -100,7 +97,7 @@ enum protocolEnum { | |||
| 100 | /* Netbios frames protocol not supported at this time */ | 97 | /* Netbios frames protocol not supported at this time */ |
| 101 | }; | 98 | }; |
| 102 | 99 | ||
| 103 | struct session_key { | 100 | struct mac_key { |
| 104 | unsigned int len; | 101 | unsigned int len; |
| 105 | union { | 102 | union { |
| 106 | char ntlm[CIFS_SESS_KEY_SIZE + 16]; | 103 | char ntlm[CIFS_SESS_KEY_SIZE + 16]; |
| @@ -123,21 +120,6 @@ struct cifs_cred { | |||
| 123 | struct cifs_ace *aces; | 120 | struct cifs_ace *aces; |
| 124 | }; | 121 | }; |
| 125 | 122 | ||
| 126 | struct sdesc { | ||
| 127 | struct shash_desc shash; | ||
| 128 | char ctx[]; | ||
| 129 | }; | ||
| 130 | |||
| 131 | struct ntlmssp_auth { | ||
| 132 | __u32 client_flags; | ||
| 133 | __u32 server_flags; | ||
| 134 | unsigned char ciphertext[CIFS_CPHTXT_SIZE]; | ||
| 135 | struct crypto_shash *hmacmd5; | ||
| 136 | struct crypto_shash *md5; | ||
| 137 | struct sdesc *sdeschmacmd5; | ||
| 138 | struct sdesc *sdescmd5; | ||
| 139 | }; | ||
| 140 | |||
| 141 | /* | 123 | /* |
| 142 | ***************************************************************** | 124 | ***************************************************************** |
| 143 | * Except the CIFS PDUs themselves all the | 125 | * Except the CIFS PDUs themselves all the |
| @@ -200,14 +182,11 @@ struct TCP_Server_Info { | |||
| 200 | /* 16th byte of RFC1001 workstation name is always null */ | 182 | /* 16th byte of RFC1001 workstation name is always null */ |
| 201 | char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; | 183 | char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; |
| 202 | __u32 sequence_number; /* needed for CIFS PDU signature */ | 184 | __u32 sequence_number; /* needed for CIFS PDU signature */ |
| 203 | struct session_key session_key; | 185 | struct mac_key mac_signing_key; |
| 204 | char ntlmv2_hash[16]; | 186 | char ntlmv2_hash[16]; |
| 205 | unsigned long lstrp; /* when we got last response from this server */ | 187 | unsigned long lstrp; /* when we got last response from this server */ |
| 206 | u16 dialect; /* dialect index that server chose */ | 188 | u16 dialect; /* dialect index that server chose */ |
| 207 | /* extended security flavors that server supports */ | 189 | /* extended security flavors that server supports */ |
| 208 | unsigned int tilen; /* length of the target info blob */ | ||
| 209 | unsigned char *tiblob; /* target info blob in challenge response */ | ||
| 210 | struct ntlmssp_auth ntlmssp; /* various keys, ciphers, flags */ | ||
| 211 | bool sec_kerberos; /* supports plain Kerberos */ | 190 | bool sec_kerberos; /* supports plain Kerberos */ |
| 212 | bool sec_mskerberos; /* supports legacy MS Kerberos */ | 191 | bool sec_mskerberos; /* supports legacy MS Kerberos */ |
| 213 | bool sec_kerberosu2u; /* supports U2U Kerberos */ | 192 | bool sec_kerberosu2u; /* supports U2U Kerberos */ |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 320e0fd0ba7b..14d036d8db11 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
| @@ -134,12 +134,6 @@ | |||
| 134 | * Size of the session key (crypto key encrypted with the password | 134 | * Size of the session key (crypto key encrypted with the password |
| 135 | */ | 135 | */ |
| 136 | #define CIFS_SESS_KEY_SIZE (24) | 136 | #define CIFS_SESS_KEY_SIZE (24) |
| 137 | #define CIFS_CLIENT_CHALLENGE_SIZE (8) | ||
| 138 | #define CIFS_SERVER_CHALLENGE_SIZE (8) | ||
| 139 | #define CIFS_HMAC_MD5_HASH_SIZE (16) | ||
| 140 | #define CIFS_CPHTXT_SIZE (16) | ||
| 141 | #define CIFS_NTLMV2_SESSKEY_SIZE (16) | ||
| 142 | #define CIFS_NTHASH_SIZE (16) | ||
| 143 | 137 | ||
| 144 | /* | 138 | /* |
| 145 | * Maximum user name length | 139 | * Maximum user name length |
| @@ -669,6 +663,7 @@ struct ntlmv2_resp { | |||
| 669 | __le64 time; | 663 | __le64 time; |
| 670 | __u64 client_chal; /* random */ | 664 | __u64 client_chal; /* random */ |
| 671 | __u32 reserved2; | 665 | __u32 reserved2; |
| 666 | struct ntlmssp2_name names[2]; | ||
| 672 | /* array of name entries could follow ending in minimum 4 byte struct */ | 667 | /* array of name entries could follow ending in minimum 4 byte struct */ |
| 673 | } __attribute__((packed)); | 668 | } __attribute__((packed)); |
| 674 | 669 | ||
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 1378d9133844..1d60c655e3e0 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
| @@ -87,8 +87,9 @@ extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); | |||
| 87 | extern int decode_negTokenInit(unsigned char *security_blob, int length, | 87 | extern int decode_negTokenInit(unsigned char *security_blob, int length, |
| 88 | struct TCP_Server_Info *server); | 88 | struct TCP_Server_Info *server); |
| 89 | extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len); | 89 | extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len); |
| 90 | extern int cifs_set_port(struct sockaddr *addr, const unsigned short int port); | ||
| 90 | extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len, | 91 | extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len, |
| 91 | unsigned short int port); | 92 | const unsigned short int port); |
| 92 | extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr); | 93 | extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr); |
| 93 | extern void header_assemble(struct smb_hdr *, char /* command */ , | 94 | extern void header_assemble(struct smb_hdr *, char /* command */ , |
| 94 | const struct cifsTconInfo *, int /* length of | 95 | const struct cifsTconInfo *, int /* length of |
| @@ -361,15 +362,13 @@ extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *); | |||
| 361 | extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, | 362 | extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, |
| 362 | __u32 *); | 363 | __u32 *); |
| 363 | extern int cifs_verify_signature(struct smb_hdr *, | 364 | extern int cifs_verify_signature(struct smb_hdr *, |
| 364 | struct TCP_Server_Info *server, | 365 | const struct mac_key *mac_key, |
| 365 | __u32 expected_sequence_number); | 366 | __u32 expected_sequence_number); |
| 366 | extern int cifs_calculate_session_key(struct session_key *key, const char *rn, | 367 | extern int cifs_calculate_mac_key(struct mac_key *key, const char *rn, |
| 367 | const char *pass); | 368 | const char *pass); |
| 368 | extern int setup_ntlmv2_rsp(struct cifsSesInfo *, char *, | 369 | extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *); |
| 370 | extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *, | ||
| 369 | const struct nls_table *); | 371 | const struct nls_table *); |
| 370 | extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *); | ||
| 371 | extern void cifs_crypto_shash_release(struct TCP_Server_Info *); | ||
| 372 | extern int calc_seckey(struct TCP_Server_Info *); | ||
| 373 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 372 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
| 374 | extern void calc_lanman_hash(const char *password, const char *cryptkey, | 373 | extern void calc_lanman_hash(const char *password, const char *cryptkey, |
| 375 | bool encrypt, char *lnm_session_key); | 374 | bool encrypt, char *lnm_session_key); |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 4bda920d1f75..c65c3419dd37 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -604,14 +604,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
| 604 | else | 604 | else |
| 605 | rc = -EINVAL; | 605 | rc = -EINVAL; |
| 606 | 606 | ||
| 607 | if (server->secType == Kerberos) { | 607 | if (server->sec_kerberos || server->sec_mskerberos) |
| 608 | if (!server->sec_kerberos && | 608 | server->secType = Kerberos; |
| 609 | !server->sec_mskerberos) | 609 | else if (server->sec_ntlmssp) |
| 610 | rc = -EOPNOTSUPP; | 610 | server->secType = RawNTLMSSP; |
| 611 | } else if (server->secType == RawNTLMSSP) { | 611 | else |
| 612 | if (!server->sec_ntlmssp) | ||
| 613 | rc = -EOPNOTSUPP; | ||
| 614 | } else | ||
| 615 | rc = -EOPNOTSUPP; | 612 | rc = -EOPNOTSUPP; |
| 616 | } | 613 | } |
| 617 | } else | 614 | } else |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index ec0ea4a43bdb..88c84a38bccb 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -400,7 +400,9 @@ incomplete_rcv: | |||
| 400 | cFYI(1, "call to reconnect done"); | 400 | cFYI(1, "call to reconnect done"); |
| 401 | csocket = server->ssocket; | 401 | csocket = server->ssocket; |
| 402 | continue; | 402 | continue; |
| 403 | } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { | 403 | } else if (length == -ERESTARTSYS || |
| 404 | length == -EAGAIN || | ||
| 405 | length == -EINTR) { | ||
| 404 | msleep(1); /* minimum sleep to prevent looping | 406 | msleep(1); /* minimum sleep to prevent looping |
| 405 | allowing socket to clear and app threads to set | 407 | allowing socket to clear and app threads to set |
| 406 | tcpStatus CifsNeedReconnect if server hung */ | 408 | tcpStatus CifsNeedReconnect if server hung */ |
| @@ -414,18 +416,6 @@ incomplete_rcv: | |||
| 414 | } else | 416 | } else |
| 415 | continue; | 417 | continue; |
| 416 | } else if (length <= 0) { | 418 | } else if (length <= 0) { |
| 417 | if (server->tcpStatus == CifsNew) { | ||
| 418 | cFYI(1, "tcp session abend after SMBnegprot"); | ||
| 419 | /* some servers kill the TCP session rather than | ||
| 420 | returning an SMB negprot error, in which | ||
| 421 | case reconnecting here is not going to help, | ||
| 422 | and so simply return error to mount */ | ||
| 423 | break; | ||
| 424 | } | ||
| 425 | if (!try_to_freeze() && (length == -EINTR)) { | ||
| 426 | cFYI(1, "cifsd thread killed"); | ||
| 427 | break; | ||
| 428 | } | ||
| 429 | cFYI(1, "Reconnect after unexpected peek error %d", | 419 | cFYI(1, "Reconnect after unexpected peek error %d", |
| 430 | length); | 420 | length); |
| 431 | cifs_reconnect(server); | 421 | cifs_reconnect(server); |
| @@ -466,27 +456,19 @@ incomplete_rcv: | |||
| 466 | an error on SMB negprot response */ | 456 | an error on SMB negprot response */ |
| 467 | cFYI(1, "Negative RFC1002 Session Response Error 0x%x)", | 457 | cFYI(1, "Negative RFC1002 Session Response Error 0x%x)", |
| 468 | pdu_length); | 458 | pdu_length); |
| 469 | if (server->tcpStatus == CifsNew) { | 459 | /* give server a second to clean up */ |
| 470 | /* if nack on negprot (rather than | 460 | msleep(1000); |
| 471 | ret of smb negprot error) reconnecting | 461 | /* always try 445 first on reconnect since we get NACK |
| 472 | not going to help, ret error to mount */ | 462 | * on some if we ever connected to port 139 (the NACK |
| 473 | break; | 463 | * is since we do not begin with RFC1001 session |
| 474 | } else { | 464 | * initialize frame) |
| 475 | /* give server a second to | 465 | */ |
| 476 | clean up before reconnect attempt */ | 466 | cifs_set_port((struct sockaddr *) |
| 477 | msleep(1000); | 467 | &server->addr.sockAddr, CIFS_PORT); |
| 478 | /* always try 445 first on reconnect | 468 | cifs_reconnect(server); |
| 479 | since we get NACK on some if we ever | 469 | csocket = server->ssocket; |
| 480 | connected to port 139 (the NACK is | 470 | wake_up(&server->response_q); |
| 481 | since we do not begin with RFC1001 | 471 | continue; |
| 482 | session initialize frame) */ | ||
| 483 | server->addr.sockAddr.sin_port = | ||
| 484 | htons(CIFS_PORT); | ||
| 485 | cifs_reconnect(server); | ||
| 486 | csocket = server->ssocket; | ||
| 487 | wake_up(&server->response_q); | ||
| 488 | continue; | ||
| 489 | } | ||
| 490 | } else if (temp != (char) 0) { | 472 | } else if (temp != (char) 0) { |
| 491 | cERROR(1, "Unknown RFC 1002 frame"); | 473 | cERROR(1, "Unknown RFC 1002 frame"); |
| 492 | cifs_dump_mem(" Received Data: ", (char *)smb_buffer, | 474 | cifs_dump_mem(" Received Data: ", (char *)smb_buffer, |
| @@ -522,8 +504,7 @@ incomplete_rcv: | |||
| 522 | total_read += length) { | 504 | total_read += length) { |
| 523 | length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, | 505 | length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, |
| 524 | pdu_length - total_read, 0); | 506 | pdu_length - total_read, 0); |
| 525 | if ((server->tcpStatus == CifsExiting) || | 507 | if (server->tcpStatus == CifsExiting) { |
| 526 | (length == -EINTR)) { | ||
| 527 | /* then will exit */ | 508 | /* then will exit */ |
| 528 | reconnect = 2; | 509 | reconnect = 2; |
| 529 | break; | 510 | break; |
| @@ -534,8 +515,9 @@ incomplete_rcv: | |||
| 534 | /* Now we will reread sock */ | 515 | /* Now we will reread sock */ |
| 535 | reconnect = 1; | 516 | reconnect = 1; |
| 536 | break; | 517 | break; |
| 537 | } else if ((length == -ERESTARTSYS) || | 518 | } else if (length == -ERESTARTSYS || |
| 538 | (length == -EAGAIN)) { | 519 | length == -EAGAIN || |
| 520 | length == -EINTR) { | ||
| 539 | msleep(1); /* minimum sleep to prevent looping, | 521 | msleep(1); /* minimum sleep to prevent looping, |
| 540 | allowing socket to clear and app | 522 | allowing socket to clear and app |
| 541 | threads to set tcpStatus | 523 | threads to set tcpStatus |
| @@ -1708,7 +1690,6 @@ cifs_put_smb_ses(struct cifsSesInfo *ses) | |||
| 1708 | CIFSSMBLogoff(xid, ses); | 1690 | CIFSSMBLogoff(xid, ses); |
| 1709 | _FreeXid(xid); | 1691 | _FreeXid(xid); |
| 1710 | } | 1692 | } |
| 1711 | cifs_crypto_shash_release(server); | ||
| 1712 | sesInfoFree(ses); | 1693 | sesInfoFree(ses); |
| 1713 | cifs_put_tcp_session(server); | 1694 | cifs_put_tcp_session(server); |
| 1714 | } | 1695 | } |
| @@ -1725,9 +1706,6 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
| 1725 | if (ses) { | 1706 | if (ses) { |
| 1726 | cFYI(1, "Existing smb sess found (status=%d)", ses->status); | 1707 | cFYI(1, "Existing smb sess found (status=%d)", ses->status); |
| 1727 | 1708 | ||
| 1728 | /* existing SMB ses has a server reference already */ | ||
| 1729 | cifs_put_tcp_session(server); | ||
| 1730 | |||
| 1731 | mutex_lock(&ses->session_mutex); | 1709 | mutex_lock(&ses->session_mutex); |
| 1732 | rc = cifs_negotiate_protocol(xid, ses); | 1710 | rc = cifs_negotiate_protocol(xid, ses); |
| 1733 | if (rc) { | 1711 | if (rc) { |
| @@ -1750,6 +1728,9 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
| 1750 | } | 1728 | } |
| 1751 | } | 1729 | } |
| 1752 | mutex_unlock(&ses->session_mutex); | 1730 | mutex_unlock(&ses->session_mutex); |
| 1731 | |||
| 1732 | /* existing SMB ses has a server reference already */ | ||
| 1733 | cifs_put_tcp_session(server); | ||
| 1753 | FreeXid(xid); | 1734 | FreeXid(xid); |
| 1754 | return ses; | 1735 | return ses; |
| 1755 | } | 1736 | } |
| @@ -1788,23 +1769,13 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
| 1788 | ses->linux_uid = volume_info->linux_uid; | 1769 | ses->linux_uid = volume_info->linux_uid; |
| 1789 | ses->overrideSecFlg = volume_info->secFlg; | 1770 | ses->overrideSecFlg = volume_info->secFlg; |
| 1790 | 1771 | ||
| 1791 | rc = cifs_crypto_shash_allocate(server); | ||
| 1792 | if (rc) { | ||
| 1793 | cERROR(1, "could not setup hash structures rc %d", rc); | ||
| 1794 | goto get_ses_fail; | ||
| 1795 | } | ||
| 1796 | server->tilen = 0; | ||
| 1797 | server->tiblob = NULL; | ||
| 1798 | |||
| 1799 | mutex_lock(&ses->session_mutex); | 1772 | mutex_lock(&ses->session_mutex); |
| 1800 | rc = cifs_negotiate_protocol(xid, ses); | 1773 | rc = cifs_negotiate_protocol(xid, ses); |
| 1801 | if (!rc) | 1774 | if (!rc) |
| 1802 | rc = cifs_setup_session(xid, ses, volume_info->local_nls); | 1775 | rc = cifs_setup_session(xid, ses, volume_info->local_nls); |
| 1803 | mutex_unlock(&ses->session_mutex); | 1776 | mutex_unlock(&ses->session_mutex); |
| 1804 | if (rc) { | 1777 | if (rc) |
| 1805 | cifs_crypto_shash_release(ses->server); | ||
| 1806 | goto get_ses_fail; | 1778 | goto get_ses_fail; |
| 1807 | } | ||
| 1808 | 1779 | ||
| 1809 | /* success, put it on the list */ | 1780 | /* success, put it on the list */ |
| 1810 | write_lock(&cifs_tcp_ses_lock); | 1781 | write_lock(&cifs_tcp_ses_lock); |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 86a164f08a74..93f77d438d3c 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -1462,29 +1462,18 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry, | |||
| 1462 | { | 1462 | { |
| 1463 | char *fromName = NULL; | 1463 | char *fromName = NULL; |
| 1464 | char *toName = NULL; | 1464 | char *toName = NULL; |
| 1465 | struct cifs_sb_info *cifs_sb_source; | 1465 | struct cifs_sb_info *cifs_sb; |
| 1466 | struct cifs_sb_info *cifs_sb_target; | ||
| 1467 | struct cifsTconInfo *tcon; | 1466 | struct cifsTconInfo *tcon; |
| 1468 | FILE_UNIX_BASIC_INFO *info_buf_source = NULL; | 1467 | FILE_UNIX_BASIC_INFO *info_buf_source = NULL; |
| 1469 | FILE_UNIX_BASIC_INFO *info_buf_target; | 1468 | FILE_UNIX_BASIC_INFO *info_buf_target; |
| 1470 | int xid, rc, tmprc; | 1469 | int xid, rc, tmprc; |
| 1471 | 1470 | ||
| 1472 | cifs_sb_target = CIFS_SB(target_dir->i_sb); | 1471 | cifs_sb = CIFS_SB(source_dir->i_sb); |
| 1473 | cifs_sb_source = CIFS_SB(source_dir->i_sb); | 1472 | tcon = cifs_sb->tcon; |
| 1474 | tcon = cifs_sb_source->tcon; | ||
| 1475 | 1473 | ||
| 1476 | xid = GetXid(); | 1474 | xid = GetXid(); |
| 1477 | 1475 | ||
| 1478 | /* | 1476 | /* |
| 1479 | * BB: this might be allowed if same server, but different share. | ||
| 1480 | * Consider adding support for this | ||
| 1481 | */ | ||
| 1482 | if (tcon != cifs_sb_target->tcon) { | ||
| 1483 | rc = -EXDEV; | ||
| 1484 | goto cifs_rename_exit; | ||
| 1485 | } | ||
| 1486 | |||
| 1487 | /* | ||
| 1488 | * we already have the rename sem so we do not need to | 1477 | * we already have the rename sem so we do not need to |
| 1489 | * grab it again here to protect the path integrity | 1478 | * grab it again here to protect the path integrity |
| 1490 | */ | 1479 | */ |
| @@ -1519,17 +1508,16 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry, | |||
| 1519 | info_buf_target = info_buf_source + 1; | 1508 | info_buf_target = info_buf_source + 1; |
| 1520 | tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName, | 1509 | tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName, |
| 1521 | info_buf_source, | 1510 | info_buf_source, |
| 1522 | cifs_sb_source->local_nls, | 1511 | cifs_sb->local_nls, |
| 1523 | cifs_sb_source->mnt_cifs_flags & | 1512 | cifs_sb->mnt_cifs_flags & |
| 1524 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1513 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 1525 | if (tmprc != 0) | 1514 | if (tmprc != 0) |
| 1526 | goto unlink_target; | 1515 | goto unlink_target; |
| 1527 | 1516 | ||
| 1528 | tmprc = CIFSSMBUnixQPathInfo(xid, tcon, | 1517 | tmprc = CIFSSMBUnixQPathInfo(xid, tcon, toName, |
| 1529 | toName, info_buf_target, | 1518 | info_buf_target, |
| 1530 | cifs_sb_target->local_nls, | 1519 | cifs_sb->local_nls, |
| 1531 | /* remap based on source sb */ | 1520 | cifs_sb->mnt_cifs_flags & |
| 1532 | cifs_sb_source->mnt_cifs_flags & | ||
| 1533 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1521 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 1534 | 1522 | ||
| 1535 | if (tmprc == 0 && (info_buf_source->UniqueId == | 1523 | if (tmprc == 0 && (info_buf_source->UniqueId == |
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index f97851119e6c..9aad47a2d62f 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c | |||
| @@ -206,26 +206,30 @@ cifs_convert_address(struct sockaddr *dst, const char *src, int len) | |||
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | int | 208 | int |
| 209 | cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len, | 209 | cifs_set_port(struct sockaddr *addr, const unsigned short int port) |
| 210 | const unsigned short int port) | ||
| 211 | { | 210 | { |
| 212 | if (!cifs_convert_address(dst, src, len)) | 211 | switch (addr->sa_family) { |
| 213 | return 0; | ||
| 214 | |||
| 215 | switch (dst->sa_family) { | ||
| 216 | case AF_INET: | 212 | case AF_INET: |
| 217 | ((struct sockaddr_in *)dst)->sin_port = htons(port); | 213 | ((struct sockaddr_in *)addr)->sin_port = htons(port); |
| 218 | break; | 214 | break; |
| 219 | case AF_INET6: | 215 | case AF_INET6: |
| 220 | ((struct sockaddr_in6 *)dst)->sin6_port = htons(port); | 216 | ((struct sockaddr_in6 *)addr)->sin6_port = htons(port); |
| 221 | break; | 217 | break; |
| 222 | default: | 218 | default: |
| 223 | return 0; | 219 | return 0; |
| 224 | } | 220 | } |
| 225 | |||
| 226 | return 1; | 221 | return 1; |
| 227 | } | 222 | } |
| 228 | 223 | ||
| 224 | int | ||
| 225 | cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len, | ||
| 226 | const unsigned short int port) | ||
| 227 | { | ||
| 228 | if (!cifs_convert_address(dst, src, len)) | ||
| 229 | return 0; | ||
| 230 | return cifs_set_port(dst, port); | ||
| 231 | } | ||
| 232 | |||
| 229 | /***************************************************************************** | 233 | /***************************************************************************** |
| 230 | convert a NT status code to a dos class/code | 234 | convert a NT status code to a dos class/code |
| 231 | *****************************************************************************/ | 235 | *****************************************************************************/ |
diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h index 1db0f0746a5b..49c9a4e75319 100644 --- a/fs/cifs/ntlmssp.h +++ b/fs/cifs/ntlmssp.h | |||
| @@ -61,19 +61,6 @@ | |||
| 61 | #define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000 | 61 | #define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000 |
| 62 | #define NTLMSSP_NEGOTIATE_56 0x80000000 | 62 | #define NTLMSSP_NEGOTIATE_56 0x80000000 |
| 63 | 63 | ||
| 64 | /* Define AV Pair Field IDs */ | ||
| 65 | #define NTLMSSP_AV_EOL 0 | ||
| 66 | #define NTLMSSP_AV_NB_COMPUTER_NAME 1 | ||
| 67 | #define NTLMSSP_AV_NB_DOMAIN_NAME 2 | ||
| 68 | #define NTLMSSP_AV_DNS_COMPUTER_NAME 3 | ||
| 69 | #define NTLMSSP_AV_DNS_DOMAIN_NAME 4 | ||
| 70 | #define NTLMSSP_AV_DNS_TREE_NAME 5 | ||
| 71 | #define NTLMSSP_AV_FLAGS 6 | ||
| 72 | #define NTLMSSP_AV_TIMESTAMP 7 | ||
| 73 | #define NTLMSSP_AV_RESTRICTION 8 | ||
| 74 | #define NTLMSSP_AV_TARGET_NAME 9 | ||
| 75 | #define NTLMSSP_AV_CHANNEL_BINDINGS 10 | ||
| 76 | |||
| 77 | /* Although typedefs are not commonly used for structure definitions */ | 64 | /* Although typedefs are not commonly used for structure definitions */ |
| 78 | /* in the Linux kernel, in this particular case they are useful */ | 65 | /* in the Linux kernel, in this particular case they are useful */ |
| 79 | /* to more closely match the standards document for NTLMSSP from */ | 66 | /* to more closely match the standards document for NTLMSSP from */ |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 795095f4eac6..0a57cb7db5dd 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
| @@ -383,9 +383,6 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft, | |||
| 383 | static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, | 383 | static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, |
| 384 | struct cifsSesInfo *ses) | 384 | struct cifsSesInfo *ses) |
| 385 | { | 385 | { |
| 386 | unsigned int tioffset; /* challeng message target info area */ | ||
| 387 | unsigned int tilen; /* challeng message target info area length */ | ||
| 388 | |||
| 389 | CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr; | 386 | CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr; |
| 390 | 387 | ||
| 391 | if (blob_len < sizeof(CHALLENGE_MESSAGE)) { | 388 | if (blob_len < sizeof(CHALLENGE_MESSAGE)) { |
| @@ -408,20 +405,6 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, | |||
| 408 | /* BB spec says that if AvId field of MsvAvTimestamp is populated then | 405 | /* BB spec says that if AvId field of MsvAvTimestamp is populated then |
| 409 | we must set the MIC field of the AUTHENTICATE_MESSAGE */ | 406 | we must set the MIC field of the AUTHENTICATE_MESSAGE */ |
| 410 | 407 | ||
| 411 | ses->server->ntlmssp.server_flags = le32_to_cpu(pblob->NegotiateFlags); | ||
| 412 | |||
| 413 | tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset); | ||
| 414 | tilen = cpu_to_le16(pblob->TargetInfoArray.Length); | ||
| 415 | ses->server->tilen = tilen; | ||
| 416 | if (tilen) { | ||
| 417 | ses->server->tiblob = kmalloc(tilen, GFP_KERNEL); | ||
| 418 | if (!ses->server->tiblob) { | ||
| 419 | cERROR(1, "Challenge target info allocation failure"); | ||
| 420 | return -ENOMEM; | ||
| 421 | } | ||
| 422 | memcpy(ses->server->tiblob, bcc_ptr + tioffset, tilen); | ||
| 423 | } | ||
| 424 | |||
| 425 | return 0; | 408 | return 0; |
| 426 | } | 409 | } |
| 427 | 410 | ||
| @@ -442,13 +425,12 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, | |||
| 442 | /* BB is NTLMV2 session security format easier to use here? */ | 425 | /* BB is NTLMV2 session security format easier to use here? */ |
| 443 | flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | | 426 | flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | |
| 444 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | | 427 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | |
| 445 | NTLMSSP_NEGOTIATE_NTLM; | 428 | NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; |
| 446 | if (ses->server->secMode & | 429 | if (ses->server->secMode & |
| 447 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { | 430 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) |
| 448 | flags |= NTLMSSP_NEGOTIATE_SIGN | | 431 | flags |= NTLMSSP_NEGOTIATE_SIGN; |
| 449 | NTLMSSP_NEGOTIATE_KEY_XCH | | 432 | if (ses->server->secMode & SECMODE_SIGN_REQUIRED) |
| 450 | NTLMSSP_NEGOTIATE_EXTENDED_SEC; | 433 | flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; |
| 451 | } | ||
| 452 | 434 | ||
| 453 | sec_blob->NegotiateFlags |= cpu_to_le32(flags); | 435 | sec_blob->NegotiateFlags |= cpu_to_le32(flags); |
| 454 | 436 | ||
| @@ -469,12 +451,10 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
| 469 | struct cifsSesInfo *ses, | 451 | struct cifsSesInfo *ses, |
| 470 | const struct nls_table *nls_cp, bool first) | 452 | const struct nls_table *nls_cp, bool first) |
| 471 | { | 453 | { |
| 472 | int rc; | ||
| 473 | unsigned int size; | ||
| 474 | AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; | 454 | AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; |
| 475 | __u32 flags; | 455 | __u32 flags; |
| 476 | unsigned char *tmp; | 456 | unsigned char *tmp; |
| 477 | struct ntlmv2_resp ntlmv2_response = {}; | 457 | char ntlm_session_key[CIFS_SESS_KEY_SIZE]; |
| 478 | 458 | ||
| 479 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); | 459 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); |
| 480 | sec_blob->MessageType = NtLmAuthenticate; | 460 | sec_blob->MessageType = NtLmAuthenticate; |
| @@ -497,25 +477,19 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
| 497 | sec_blob->LmChallengeResponse.Length = 0; | 477 | sec_blob->LmChallengeResponse.Length = 0; |
| 498 | sec_blob->LmChallengeResponse.MaximumLength = 0; | 478 | sec_blob->LmChallengeResponse.MaximumLength = 0; |
| 499 | 479 | ||
| 500 | sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); | 480 | /* calculate session key, BB what about adding similar ntlmv2 path? */ |
| 501 | rc = setup_ntlmv2_rsp(ses, (char *)&ntlmv2_response, nls_cp); | 481 | SMBNTencrypt(ses->password, ses->server->cryptKey, ntlm_session_key); |
| 502 | if (rc) { | 482 | if (first) |
| 503 | cERROR(1, "error rc: %d during ntlmssp ntlmv2 setup", rc); | 483 | cifs_calculate_mac_key(&ses->server->mac_signing_key, |
| 504 | goto setup_ntlmv2_ret; | 484 | ntlm_session_key, ses->password); |
| 505 | } | ||
| 506 | size = sizeof(struct ntlmv2_resp); | ||
| 507 | memcpy(tmp, (char *)&ntlmv2_response, size); | ||
| 508 | tmp += size; | ||
| 509 | if (ses->server->tilen > 0) { | ||
| 510 | memcpy(tmp, ses->server->tiblob, ses->server->tilen); | ||
| 511 | tmp += ses->server->tilen; | ||
| 512 | } else | ||
| 513 | ses->server->tilen = 0; | ||
| 514 | 485 | ||
| 515 | sec_blob->NtChallengeResponse.Length = cpu_to_le16(size + | 486 | memcpy(tmp, ntlm_session_key, CIFS_SESS_KEY_SIZE); |
| 516 | ses->server->tilen); | 487 | sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); |
| 488 | sec_blob->NtChallengeResponse.Length = cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
| 517 | sec_blob->NtChallengeResponse.MaximumLength = | 489 | sec_blob->NtChallengeResponse.MaximumLength = |
| 518 | cpu_to_le16(size + ses->server->tilen); | 490 | cpu_to_le16(CIFS_SESS_KEY_SIZE); |
| 491 | |||
| 492 | tmp += CIFS_SESS_KEY_SIZE; | ||
| 519 | 493 | ||
| 520 | if (ses->domainName == NULL) { | 494 | if (ses->domainName == NULL) { |
| 521 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); | 495 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); |
| @@ -527,6 +501,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
| 527 | len = cifs_strtoUCS((__le16 *)tmp, ses->domainName, | 501 | len = cifs_strtoUCS((__le16 *)tmp, ses->domainName, |
| 528 | MAX_USERNAME_SIZE, nls_cp); | 502 | MAX_USERNAME_SIZE, nls_cp); |
| 529 | len *= 2; /* unicode is 2 bytes each */ | 503 | len *= 2; /* unicode is 2 bytes each */ |
| 504 | len += 2; /* trailing null */ | ||
| 530 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); | 505 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); |
| 531 | sec_blob->DomainName.Length = cpu_to_le16(len); | 506 | sec_blob->DomainName.Length = cpu_to_le16(len); |
| 532 | sec_blob->DomainName.MaximumLength = cpu_to_le16(len); | 507 | sec_blob->DomainName.MaximumLength = cpu_to_le16(len); |
| @@ -543,6 +518,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
| 543 | len = cifs_strtoUCS((__le16 *)tmp, ses->userName, | 518 | len = cifs_strtoUCS((__le16 *)tmp, ses->userName, |
| 544 | MAX_USERNAME_SIZE, nls_cp); | 519 | MAX_USERNAME_SIZE, nls_cp); |
| 545 | len *= 2; /* unicode is 2 bytes each */ | 520 | len *= 2; /* unicode is 2 bytes each */ |
| 521 | len += 2; /* trailing null */ | ||
| 546 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); | 522 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); |
| 547 | sec_blob->UserName.Length = cpu_to_le16(len); | 523 | sec_blob->UserName.Length = cpu_to_le16(len); |
| 548 | sec_blob->UserName.MaximumLength = cpu_to_le16(len); | 524 | sec_blob->UserName.MaximumLength = cpu_to_le16(len); |
| @@ -554,26 +530,9 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
| 554 | sec_blob->WorkstationName.MaximumLength = 0; | 530 | sec_blob->WorkstationName.MaximumLength = 0; |
| 555 | tmp += 2; | 531 | tmp += 2; |
| 556 | 532 | ||
| 557 | if ((ses->server->ntlmssp.server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) && | 533 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); |
| 558 | !calc_seckey(ses->server)) { | 534 | sec_blob->SessionKey.Length = 0; |
| 559 | memcpy(tmp, ses->server->ntlmssp.ciphertext, CIFS_CPHTXT_SIZE); | 535 | sec_blob->SessionKey.MaximumLength = 0; |
| 560 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
| 561 | sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE); | ||
| 562 | sec_blob->SessionKey.MaximumLength = | ||
| 563 | cpu_to_le16(CIFS_CPHTXT_SIZE); | ||
| 564 | tmp += CIFS_CPHTXT_SIZE; | ||
| 565 | } else { | ||
| 566 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
| 567 | sec_blob->SessionKey.Length = 0; | ||
| 568 | sec_blob->SessionKey.MaximumLength = 0; | ||
| 569 | } | ||
| 570 | |||
| 571 | ses->server->sequence_number = 0; | ||
| 572 | |||
| 573 | setup_ntlmv2_ret: | ||
| 574 | if (ses->server->tilen > 0) | ||
| 575 | kfree(ses->server->tiblob); | ||
| 576 | |||
| 577 | return tmp - pbuffer; | 536 | return tmp - pbuffer; |
| 578 | } | 537 | } |
| 579 | 538 | ||
| @@ -587,14 +546,15 @@ static void setup_ntlmssp_neg_req(SESSION_SETUP_ANDX *pSMB, | |||
| 587 | return; | 546 | return; |
| 588 | } | 547 | } |
| 589 | 548 | ||
| 590 | static int setup_ntlmssp_auth_req(char *ntlmsspblob, | 549 | static int setup_ntlmssp_auth_req(SESSION_SETUP_ANDX *pSMB, |
| 591 | struct cifsSesInfo *ses, | 550 | struct cifsSesInfo *ses, |
| 592 | const struct nls_table *nls, bool first_time) | 551 | const struct nls_table *nls, bool first_time) |
| 593 | { | 552 | { |
| 594 | int bloblen; | 553 | int bloblen; |
| 595 | 554 | ||
| 596 | bloblen = build_ntlmssp_auth_blob(ntlmsspblob, ses, nls, | 555 | bloblen = build_ntlmssp_auth_blob(&pSMB->req.SecurityBlob[0], ses, nls, |
| 597 | first_time); | 556 | first_time); |
| 557 | pSMB->req.SecurityBlobLength = cpu_to_le16(bloblen); | ||
| 598 | 558 | ||
| 599 | return bloblen; | 559 | return bloblen; |
| 600 | } | 560 | } |
| @@ -730,7 +690,7 @@ ssetup_ntlmssp_authenticate: | |||
| 730 | 690 | ||
| 731 | if (first_time) /* should this be moved into common code | 691 | if (first_time) /* should this be moved into common code |
| 732 | with similar ntlmv2 path? */ | 692 | with similar ntlmv2 path? */ |
| 733 | cifs_calculate_session_key(&ses->server->session_key, | 693 | cifs_calculate_mac_key(&ses->server->mac_signing_key, |
| 734 | ntlm_session_key, ses->password); | 694 | ntlm_session_key, ses->password); |
| 735 | /* copy session key */ | 695 | /* copy session key */ |
| 736 | 696 | ||
| @@ -769,21 +729,12 @@ ssetup_ntlmssp_authenticate: | |||
| 769 | cpu_to_le16(sizeof(struct ntlmv2_resp)); | 729 | cpu_to_le16(sizeof(struct ntlmv2_resp)); |
| 770 | 730 | ||
| 771 | /* calculate session key */ | 731 | /* calculate session key */ |
| 772 | rc = setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); | 732 | setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); |
| 773 | if (rc) { | ||
| 774 | kfree(v2_sess_key); | ||
| 775 | goto ssetup_exit; | ||
| 776 | } | ||
| 777 | /* FIXME: calculate MAC key */ | 733 | /* FIXME: calculate MAC key */ |
| 778 | memcpy(bcc_ptr, (char *)v2_sess_key, | 734 | memcpy(bcc_ptr, (char *)v2_sess_key, |
| 779 | sizeof(struct ntlmv2_resp)); | 735 | sizeof(struct ntlmv2_resp)); |
| 780 | bcc_ptr += sizeof(struct ntlmv2_resp); | 736 | bcc_ptr += sizeof(struct ntlmv2_resp); |
| 781 | kfree(v2_sess_key); | 737 | kfree(v2_sess_key); |
| 782 | if (ses->server->tilen > 0) { | ||
| 783 | memcpy(bcc_ptr, ses->server->tiblob, | ||
| 784 | ses->server->tilen); | ||
| 785 | bcc_ptr += ses->server->tilen; | ||
| 786 | } | ||
| 787 | if (ses->capabilities & CAP_UNICODE) { | 738 | if (ses->capabilities & CAP_UNICODE) { |
| 788 | if (iov[0].iov_len % 2) { | 739 | if (iov[0].iov_len % 2) { |
| 789 | *bcc_ptr = 0; | 740 | *bcc_ptr = 0; |
| @@ -814,15 +765,15 @@ ssetup_ntlmssp_authenticate: | |||
| 814 | } | 765 | } |
| 815 | /* bail out if key is too long */ | 766 | /* bail out if key is too long */ |
| 816 | if (msg->sesskey_len > | 767 | if (msg->sesskey_len > |
| 817 | sizeof(ses->server->session_key.data.krb5)) { | 768 | sizeof(ses->server->mac_signing_key.data.krb5)) { |
| 818 | cERROR(1, "Kerberos signing key too long (%u bytes)", | 769 | cERROR(1, "Kerberos signing key too long (%u bytes)", |
| 819 | msg->sesskey_len); | 770 | msg->sesskey_len); |
| 820 | rc = -EOVERFLOW; | 771 | rc = -EOVERFLOW; |
| 821 | goto ssetup_exit; | 772 | goto ssetup_exit; |
| 822 | } | 773 | } |
| 823 | if (first_time) { | 774 | if (first_time) { |
| 824 | ses->server->session_key.len = msg->sesskey_len; | 775 | ses->server->mac_signing_key.len = msg->sesskey_len; |
| 825 | memcpy(ses->server->session_key.data.krb5, | 776 | memcpy(ses->server->mac_signing_key.data.krb5, |
| 826 | msg->data, msg->sesskey_len); | 777 | msg->data, msg->sesskey_len); |
| 827 | } | 778 | } |
| 828 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | 779 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; |
| @@ -864,28 +815,12 @@ ssetup_ntlmssp_authenticate: | |||
| 864 | if (phase == NtLmNegotiate) { | 815 | if (phase == NtLmNegotiate) { |
| 865 | setup_ntlmssp_neg_req(pSMB, ses); | 816 | setup_ntlmssp_neg_req(pSMB, ses); |
| 866 | iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); | 817 | iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); |
| 867 | iov[1].iov_base = &pSMB->req.SecurityBlob[0]; | ||
| 868 | } else if (phase == NtLmAuthenticate) { | 818 | } else if (phase == NtLmAuthenticate) { |
| 869 | int blob_len; | 819 | int blob_len; |
| 870 | char *ntlmsspblob; | 820 | blob_len = setup_ntlmssp_auth_req(pSMB, ses, |
| 871 | 821 | nls_cp, | |
| 872 | ntlmsspblob = kmalloc(5 * | 822 | first_time); |
| 873 | sizeof(struct _AUTHENTICATE_MESSAGE), | ||
| 874 | GFP_KERNEL); | ||
| 875 | if (!ntlmsspblob) { | ||
| 876 | cERROR(1, "Can't allocate NTLMSSP"); | ||
| 877 | rc = -ENOMEM; | ||
| 878 | goto ssetup_exit; | ||
| 879 | } | ||
| 880 | |||
| 881 | blob_len = setup_ntlmssp_auth_req(ntlmsspblob, | ||
| 882 | ses, | ||
| 883 | nls_cp, | ||
| 884 | first_time); | ||
| 885 | iov[1].iov_len = blob_len; | 823 | iov[1].iov_len = blob_len; |
| 886 | iov[1].iov_base = ntlmsspblob; | ||
| 887 | pSMB->req.SecurityBlobLength = | ||
| 888 | cpu_to_le16(blob_len); | ||
| 889 | /* Make sure that we tell the server that we | 824 | /* Make sure that we tell the server that we |
| 890 | are using the uid that it just gave us back | 825 | are using the uid that it just gave us back |
| 891 | on the response (challenge) */ | 826 | on the response (challenge) */ |
| @@ -895,6 +830,7 @@ ssetup_ntlmssp_authenticate: | |||
| 895 | rc = -ENOSYS; | 830 | rc = -ENOSYS; |
| 896 | goto ssetup_exit; | 831 | goto ssetup_exit; |
| 897 | } | 832 | } |
| 833 | iov[1].iov_base = &pSMB->req.SecurityBlob[0]; | ||
| 898 | /* unicode strings must be word aligned */ | 834 | /* unicode strings must be word aligned */ |
| 899 | if ((iov[0].iov_len + iov[1].iov_len) % 2) { | 835 | if ((iov[0].iov_len + iov[1].iov_len) % 2) { |
| 900 | *bcc_ptr = 0; | 836 | *bcc_ptr = 0; |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index e0588cdf4cc5..82f78c4d6978 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
| @@ -543,7 +543,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 543 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | 543 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | |
| 544 | SECMODE_SIGN_ENABLED))) { | 544 | SECMODE_SIGN_ENABLED))) { |
| 545 | rc = cifs_verify_signature(midQ->resp_buf, | 545 | rc = cifs_verify_signature(midQ->resp_buf, |
| 546 | ses->server, | 546 | &ses->server->mac_signing_key, |
| 547 | midQ->sequence_number+1); | 547 | midQ->sequence_number+1); |
| 548 | if (rc) { | 548 | if (rc) { |
| 549 | cERROR(1, "Unexpected SMB signature"); | 549 | cERROR(1, "Unexpected SMB signature"); |
| @@ -731,7 +731,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 731 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | 731 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | |
| 732 | SECMODE_SIGN_ENABLED))) { | 732 | SECMODE_SIGN_ENABLED))) { |
| 733 | rc = cifs_verify_signature(out_buf, | 733 | rc = cifs_verify_signature(out_buf, |
| 734 | ses->server, | 734 | &ses->server->mac_signing_key, |
| 735 | midQ->sequence_number+1); | 735 | midQ->sequence_number+1); |
| 736 | if (rc) { | 736 | if (rc) { |
| 737 | cERROR(1, "Unexpected SMB signature"); | 737 | cERROR(1, "Unexpected SMB signature"); |
| @@ -981,7 +981,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
| 981 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | 981 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | |
| 982 | SECMODE_SIGN_ENABLED))) { | 982 | SECMODE_SIGN_ENABLED))) { |
| 983 | rc = cifs_verify_signature(out_buf, | 983 | rc = cifs_verify_signature(out_buf, |
| 984 | ses->server, | 984 | &ses->server->mac_signing_key, |
| 985 | midQ->sequence_number+1); | 985 | midQ->sequence_number+1); |
| 986 | if (rc) { | 986 | if (rc) { |
| 987 | cERROR(1, "Unexpected SMB signature"); | 987 | cERROR(1, "Unexpected SMB signature"); |
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c index de89645777c7..116af7546cf0 100644 --- a/fs/coda/psdev.c +++ b/fs/coda/psdev.c | |||
| @@ -184,8 +184,8 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf, | |||
| 184 | } | 184 | } |
| 185 | 185 | ||
| 186 | /* adjust outsize. is this useful ?? */ | 186 | /* adjust outsize. is this useful ?? */ |
| 187 | req->uc_outSize = nbytes; | 187 | req->uc_outSize = nbytes; |
| 188 | req->uc_flags |= REQ_WRITE; | 188 | req->uc_flags |= CODA_REQ_WRITE; |
| 189 | count = nbytes; | 189 | count = nbytes; |
| 190 | 190 | ||
| 191 | /* Convert filedescriptor into a file handle */ | 191 | /* Convert filedescriptor into a file handle */ |
diff --git a/fs/direct-io.c b/fs/direct-io.c index 51f270b479b6..48d74c7391d1 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c | |||
| @@ -634,7 +634,7 @@ static int dio_send_cur_page(struct dio *dio) | |||
| 634 | int ret = 0; | 634 | int ret = 0; |
| 635 | 635 | ||
| 636 | if (dio->bio) { | 636 | if (dio->bio) { |
| 637 | loff_t cur_offset = dio->block_in_file << dio->blkbits; | 637 | loff_t cur_offset = dio->cur_page_fs_offset; |
| 638 | loff_t bio_next_offset = dio->logical_offset_in_bio + | 638 | loff_t bio_next_offset = dio->logical_offset_in_bio + |
| 639 | dio->bio->bi_size; | 639 | dio->bio->bi_size; |
| 640 | 640 | ||
| @@ -659,7 +659,7 @@ static int dio_send_cur_page(struct dio *dio) | |||
| 659 | * Submit now if the underlying fs is about to perform a | 659 | * Submit now if the underlying fs is about to perform a |
| 660 | * metadata read | 660 | * metadata read |
| 661 | */ | 661 | */ |
| 662 | if (dio->boundary) | 662 | else if (dio->boundary) |
| 663 | dio_bio_submit(dio); | 663 | dio_bio_submit(dio); |
| 664 | } | 664 | } |
| 665 | 665 | ||
| @@ -376,6 +376,9 @@ static int count(const char __user * const __user * argv, int max) | |||
| 376 | argv++; | 376 | argv++; |
| 377 | if (i++ >= max) | 377 | if (i++ >= max) |
| 378 | return -E2BIG; | 378 | return -E2BIG; |
| 379 | |||
| 380 | if (fatal_signal_pending(current)) | ||
| 381 | return -ERESTARTNOHAND; | ||
| 379 | cond_resched(); | 382 | cond_resched(); |
| 380 | } | 383 | } |
| 381 | } | 384 | } |
| @@ -419,6 +422,12 @@ static int copy_strings(int argc, const char __user *const __user *argv, | |||
| 419 | while (len > 0) { | 422 | while (len > 0) { |
| 420 | int offset, bytes_to_copy; | 423 | int offset, bytes_to_copy; |
| 421 | 424 | ||
| 425 | if (fatal_signal_pending(current)) { | ||
| 426 | ret = -ERESTARTNOHAND; | ||
| 427 | goto out; | ||
| 428 | } | ||
| 429 | cond_resched(); | ||
| 430 | |||
| 422 | offset = pos % PAGE_SIZE; | 431 | offset = pos % PAGE_SIZE; |
| 423 | if (offset == 0) | 432 | if (offset == 0) |
| 424 | offset = PAGE_SIZE; | 433 | offset = PAGE_SIZE; |
| @@ -594,6 +603,11 @@ int setup_arg_pages(struct linux_binprm *bprm, | |||
| 594 | #else | 603 | #else |
| 595 | stack_top = arch_align_stack(stack_top); | 604 | stack_top = arch_align_stack(stack_top); |
| 596 | stack_top = PAGE_ALIGN(stack_top); | 605 | stack_top = PAGE_ALIGN(stack_top); |
| 606 | |||
| 607 | if (unlikely(stack_top < mmap_min_addr) || | ||
| 608 | unlikely(vma->vm_end - vma->vm_start >= stack_top - mmap_min_addr)) | ||
| 609 | return -ENOMEM; | ||
| 610 | |||
| 597 | stack_shift = vma->vm_end - stack_top; | 611 | stack_shift = vma->vm_end - stack_top; |
| 598 | 612 | ||
| 599 | bprm->p -= stack_shift; | 613 | bprm->p -= stack_shift; |
diff --git a/fs/fcntl.c b/fs/fcntl.c index 6769fd0f35b8..f8cc34f542c3 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
| @@ -769,11 +769,15 @@ EXPORT_SYMBOL(kill_fasync); | |||
| 769 | 769 | ||
| 770 | static int __init fcntl_init(void) | 770 | static int __init fcntl_init(void) |
| 771 | { | 771 | { |
| 772 | /* please add new bits here to ensure allocation uniqueness */ | 772 | /* |
| 773 | BUILD_BUG_ON(19 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32( | 773 | * Please add new bits here to ensure allocation uniqueness. |
| 774 | * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY | ||
| 775 | * is defined as O_NONBLOCK on some platforms and not on others. | ||
| 776 | */ | ||
| 777 | BUILD_BUG_ON(18 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32( | ||
| 774 | O_RDONLY | O_WRONLY | O_RDWR | | 778 | O_RDONLY | O_WRONLY | O_RDWR | |
| 775 | O_CREAT | O_EXCL | O_NOCTTY | | 779 | O_CREAT | O_EXCL | O_NOCTTY | |
| 776 | O_TRUNC | O_APPEND | O_NONBLOCK | | 780 | O_TRUNC | O_APPEND | /* O_NONBLOCK | */ |
| 777 | __O_SYNC | O_DSYNC | FASYNC | | 781 | __O_SYNC | O_DSYNC | FASYNC | |
| 778 | O_DIRECT | O_LARGEFILE | O_DIRECTORY | | 782 | O_DIRECT | O_LARGEFILE | O_DIRECTORY | |
| 779 | O_NOFOLLOW | O_NOATIME | O_CLOEXEC | | 783 | O_NOFOLLOW | O_NOATIME | O_CLOEXEC | |
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 7d9d06ba184b..5581122bd2c0 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
| @@ -52,8 +52,6 @@ struct wb_writeback_work { | |||
| 52 | #define CREATE_TRACE_POINTS | 52 | #define CREATE_TRACE_POINTS |
| 53 | #include <trace/events/writeback.h> | 53 | #include <trace/events/writeback.h> |
| 54 | 54 | ||
| 55 | #define inode_to_bdi(inode) ((inode)->i_mapping->backing_dev_info) | ||
| 56 | |||
| 57 | /* | 55 | /* |
| 58 | * We don't actually have pdflush, but this one is exported though /proc... | 56 | * We don't actually have pdflush, but this one is exported though /proc... |
| 59 | */ | 57 | */ |
| @@ -71,6 +69,27 @@ int writeback_in_progress(struct backing_dev_info *bdi) | |||
| 71 | return test_bit(BDI_writeback_running, &bdi->state); | 69 | return test_bit(BDI_writeback_running, &bdi->state); |
| 72 | } | 70 | } |
| 73 | 71 | ||
| 72 | static inline struct backing_dev_info *inode_to_bdi(struct inode *inode) | ||
| 73 | { | ||
| 74 | struct super_block *sb = inode->i_sb; | ||
| 75 | struct backing_dev_info *bdi = inode->i_mapping->backing_dev_info; | ||
| 76 | |||
| 77 | /* | ||
| 78 | * For inodes on standard filesystems, we use superblock's bdi. For | ||
| 79 | * inodes on virtual filesystems, we want to use inode mapping's bdi | ||
| 80 | * because they can possibly point to something useful (think about | ||
| 81 | * block_dev filesystem). | ||
| 82 | */ | ||
| 83 | if (sb->s_bdi && sb->s_bdi != &noop_backing_dev_info) { | ||
| 84 | /* Some device inodes could play dirty tricks. Catch them... */ | ||
| 85 | WARN(bdi != sb->s_bdi && bdi_cap_writeback_dirty(bdi), | ||
| 86 | "Dirtiable inode bdi %s != sb bdi %s\n", | ||
| 87 | bdi->name, sb->s_bdi->name); | ||
| 88 | return sb->s_bdi; | ||
| 89 | } | ||
| 90 | return bdi; | ||
| 91 | } | ||
| 92 | |||
| 74 | static void bdi_queue_work(struct backing_dev_info *bdi, | 93 | static void bdi_queue_work(struct backing_dev_info *bdi, |
| 75 | struct wb_writeback_work *work) | 94 | struct wb_writeback_work *work) |
| 76 | { | 95 | { |
| @@ -808,7 +827,7 @@ int bdi_writeback_thread(void *data) | |||
| 808 | wb->last_active = jiffies; | 827 | wb->last_active = jiffies; |
| 809 | 828 | ||
| 810 | set_current_state(TASK_INTERRUPTIBLE); | 829 | set_current_state(TASK_INTERRUPTIBLE); |
| 811 | if (!list_empty(&bdi->work_list)) { | 830 | if (!list_empty(&bdi->work_list) || kthread_should_stop()) { |
| 812 | __set_current_state(TASK_RUNNING); | 831 | __set_current_state(TASK_RUNNING); |
| 813 | continue; | 832 | continue; |
| 814 | } | 833 | } |
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 69ad053ffd78..d367af1514ef 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
| @@ -276,7 +276,7 @@ static void flush_bg_queue(struct fuse_conn *fc) | |||
| 276 | * Called with fc->lock, unlocks it | 276 | * Called with fc->lock, unlocks it |
| 277 | */ | 277 | */ |
| 278 | static void request_end(struct fuse_conn *fc, struct fuse_req *req) | 278 | static void request_end(struct fuse_conn *fc, struct fuse_req *req) |
| 279 | __releases(&fc->lock) | 279 | __releases(fc->lock) |
| 280 | { | 280 | { |
| 281 | void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; | 281 | void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; |
| 282 | req->end = NULL; | 282 | req->end = NULL; |
| @@ -306,8 +306,8 @@ __releases(&fc->lock) | |||
| 306 | 306 | ||
| 307 | static void wait_answer_interruptible(struct fuse_conn *fc, | 307 | static void wait_answer_interruptible(struct fuse_conn *fc, |
| 308 | struct fuse_req *req) | 308 | struct fuse_req *req) |
| 309 | __releases(&fc->lock) | 309 | __releases(fc->lock) |
| 310 | __acquires(&fc->lock) | 310 | __acquires(fc->lock) |
| 311 | { | 311 | { |
| 312 | if (signal_pending(current)) | 312 | if (signal_pending(current)) |
| 313 | return; | 313 | return; |
| @@ -325,8 +325,8 @@ static void queue_interrupt(struct fuse_conn *fc, struct fuse_req *req) | |||
| 325 | } | 325 | } |
| 326 | 326 | ||
| 327 | static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) | 327 | static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) |
| 328 | __releases(&fc->lock) | 328 | __releases(fc->lock) |
| 329 | __acquires(&fc->lock) | 329 | __acquires(fc->lock) |
| 330 | { | 330 | { |
| 331 | if (!fc->no_interrupt) { | 331 | if (!fc->no_interrupt) { |
| 332 | /* Any signal may interrupt this */ | 332 | /* Any signal may interrupt this */ |
| @@ -905,8 +905,8 @@ static int request_pending(struct fuse_conn *fc) | |||
| 905 | 905 | ||
| 906 | /* Wait until a request is available on the pending list */ | 906 | /* Wait until a request is available on the pending list */ |
| 907 | static void request_wait(struct fuse_conn *fc) | 907 | static void request_wait(struct fuse_conn *fc) |
| 908 | __releases(&fc->lock) | 908 | __releases(fc->lock) |
| 909 | __acquires(&fc->lock) | 909 | __acquires(fc->lock) |
| 910 | { | 910 | { |
| 911 | DECLARE_WAITQUEUE(wait, current); | 911 | DECLARE_WAITQUEUE(wait, current); |
| 912 | 912 | ||
| @@ -934,7 +934,7 @@ __acquires(&fc->lock) | |||
| 934 | */ | 934 | */ |
| 935 | static int fuse_read_interrupt(struct fuse_conn *fc, struct fuse_copy_state *cs, | 935 | static int fuse_read_interrupt(struct fuse_conn *fc, struct fuse_copy_state *cs, |
| 936 | size_t nbytes, struct fuse_req *req) | 936 | size_t nbytes, struct fuse_req *req) |
| 937 | __releases(&fc->lock) | 937 | __releases(fc->lock) |
| 938 | { | 938 | { |
| 939 | struct fuse_in_header ih; | 939 | struct fuse_in_header ih; |
| 940 | struct fuse_interrupt_in arg; | 940 | struct fuse_interrupt_in arg; |
| @@ -1720,8 +1720,8 @@ static unsigned fuse_dev_poll(struct file *file, poll_table *wait) | |||
| 1720 | * This function releases and reacquires fc->lock | 1720 | * This function releases and reacquires fc->lock |
| 1721 | */ | 1721 | */ |
| 1722 | static void end_requests(struct fuse_conn *fc, struct list_head *head) | 1722 | static void end_requests(struct fuse_conn *fc, struct list_head *head) |
| 1723 | __releases(&fc->lock) | 1723 | __releases(fc->lock) |
| 1724 | __acquires(&fc->lock) | 1724 | __acquires(fc->lock) |
| 1725 | { | 1725 | { |
| 1726 | while (!list_empty(head)) { | 1726 | while (!list_empty(head)) { |
| 1727 | struct fuse_req *req; | 1727 | struct fuse_req *req; |
| @@ -1744,8 +1744,8 @@ __acquires(&fc->lock) | |||
| 1744 | * locked). | 1744 | * locked). |
| 1745 | */ | 1745 | */ |
| 1746 | static void end_io_requests(struct fuse_conn *fc) | 1746 | static void end_io_requests(struct fuse_conn *fc) |
| 1747 | __releases(&fc->lock) | 1747 | __releases(fc->lock) |
| 1748 | __acquires(&fc->lock) | 1748 | __acquires(fc->lock) |
| 1749 | { | 1749 | { |
| 1750 | while (!list_empty(&fc->io)) { | 1750 | while (!list_empty(&fc->io)) { |
| 1751 | struct fuse_req *req = | 1751 | struct fuse_req *req = |
| @@ -1769,6 +1769,16 @@ __acquires(&fc->lock) | |||
| 1769 | } | 1769 | } |
| 1770 | } | 1770 | } |
| 1771 | 1771 | ||
| 1772 | static void end_queued_requests(struct fuse_conn *fc) | ||
| 1773 | __releases(fc->lock) | ||
| 1774 | __acquires(fc->lock) | ||
| 1775 | { | ||
| 1776 | fc->max_background = UINT_MAX; | ||
| 1777 | flush_bg_queue(fc); | ||
| 1778 | end_requests(fc, &fc->pending); | ||
| 1779 | end_requests(fc, &fc->processing); | ||
| 1780 | } | ||
| 1781 | |||
| 1772 | /* | 1782 | /* |
| 1773 | * Abort all requests. | 1783 | * Abort all requests. |
| 1774 | * | 1784 | * |
| @@ -1795,8 +1805,7 @@ void fuse_abort_conn(struct fuse_conn *fc) | |||
| 1795 | fc->connected = 0; | 1805 | fc->connected = 0; |
| 1796 | fc->blocked = 0; | 1806 | fc->blocked = 0; |
| 1797 | end_io_requests(fc); | 1807 | end_io_requests(fc); |
| 1798 | end_requests(fc, &fc->pending); | 1808 | end_queued_requests(fc); |
| 1799 | end_requests(fc, &fc->processing); | ||
| 1800 | wake_up_all(&fc->waitq); | 1809 | wake_up_all(&fc->waitq); |
| 1801 | wake_up_all(&fc->blocked_waitq); | 1810 | wake_up_all(&fc->blocked_waitq); |
| 1802 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); | 1811 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); |
| @@ -1811,8 +1820,9 @@ int fuse_dev_release(struct inode *inode, struct file *file) | |||
| 1811 | if (fc) { | 1820 | if (fc) { |
| 1812 | spin_lock(&fc->lock); | 1821 | spin_lock(&fc->lock); |
| 1813 | fc->connected = 0; | 1822 | fc->connected = 0; |
| 1814 | end_requests(fc, &fc->pending); | 1823 | fc->blocked = 0; |
| 1815 | end_requests(fc, &fc->processing); | 1824 | end_queued_requests(fc); |
| 1825 | wake_up_all(&fc->blocked_waitq); | ||
| 1816 | spin_unlock(&fc->lock); | 1826 | spin_unlock(&fc->lock); |
| 1817 | fuse_conn_put(fc); | 1827 | fuse_conn_put(fc); |
| 1818 | } | 1828 | } |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 147c1f71bdb9..c8224587123f 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
| @@ -1144,8 +1144,8 @@ static void fuse_writepage_finish(struct fuse_conn *fc, struct fuse_req *req) | |||
| 1144 | 1144 | ||
| 1145 | /* Called under fc->lock, may release and reacquire it */ | 1145 | /* Called under fc->lock, may release and reacquire it */ |
| 1146 | static void fuse_send_writepage(struct fuse_conn *fc, struct fuse_req *req) | 1146 | static void fuse_send_writepage(struct fuse_conn *fc, struct fuse_req *req) |
| 1147 | __releases(&fc->lock) | 1147 | __releases(fc->lock) |
| 1148 | __acquires(&fc->lock) | 1148 | __acquires(fc->lock) |
| 1149 | { | 1149 | { |
| 1150 | struct fuse_inode *fi = get_fuse_inode(req->inode); | 1150 | struct fuse_inode *fi = get_fuse_inode(req->inode); |
| 1151 | loff_t size = i_size_read(req->inode); | 1151 | loff_t size = i_size_read(req->inode); |
| @@ -1183,8 +1183,8 @@ __acquires(&fc->lock) | |||
| 1183 | * Called with fc->lock | 1183 | * Called with fc->lock |
| 1184 | */ | 1184 | */ |
| 1185 | void fuse_flush_writepages(struct inode *inode) | 1185 | void fuse_flush_writepages(struct inode *inode) |
| 1186 | __releases(&fc->lock) | 1186 | __releases(fc->lock) |
| 1187 | __acquires(&fc->lock) | 1187 | __acquires(fc->lock) |
| 1188 | { | 1188 | { |
| 1189 | struct fuse_conn *fc = get_fuse_conn(inode); | 1189 | struct fuse_conn *fc = get_fuse_conn(inode); |
| 1190 | struct fuse_inode *fi = get_fuse_inode(inode); | 1190 | struct fuse_inode *fi = get_fuse_inode(inode); |
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index cde1248a6225..ac750bd31a6f 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c | |||
| @@ -932,7 +932,7 @@ int gfs2_logd(void *data) | |||
| 932 | 932 | ||
| 933 | do { | 933 | do { |
| 934 | prepare_to_wait(&sdp->sd_logd_waitq, &wait, | 934 | prepare_to_wait(&sdp->sd_logd_waitq, &wait, |
| 935 | TASK_UNINTERRUPTIBLE); | 935 | TASK_INTERRUPTIBLE); |
| 936 | if (!gfs2_ail_flush_reqd(sdp) && | 936 | if (!gfs2_ail_flush_reqd(sdp) && |
| 937 | !gfs2_jrnl_flush_reqd(sdp) && | 937 | !gfs2_jrnl_flush_reqd(sdp) && |
| 938 | !kthread_should_stop()) | 938 | !kthread_should_stop()) |
diff --git a/fs/minix/namei.c b/fs/minix/namei.c index e20ee85955d1..f3f3578393a4 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c | |||
| @@ -115,7 +115,7 @@ static int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode) | |||
| 115 | 115 | ||
| 116 | inode_inc_link_count(dir); | 116 | inode_inc_link_count(dir); |
| 117 | 117 | ||
| 118 | inode = minix_new_inode(dir, mode, &err); | 118 | inode = minix_new_inode(dir, S_IFDIR | mode, &err); |
| 119 | if (!inode) | 119 | if (!inode) |
| 120 | goto out_dir; | 120 | goto out_dir; |
| 121 | 121 | ||
diff --git a/fs/namespace.c b/fs/namespace.c index de402eb6eafb..a72eaabfe8f2 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -1484,13 +1484,30 @@ out_unlock: | |||
| 1484 | } | 1484 | } |
| 1485 | 1485 | ||
| 1486 | /* | 1486 | /* |
| 1487 | * Sanity check the flags to change_mnt_propagation. | ||
| 1488 | */ | ||
| 1489 | |||
| 1490 | static int flags_to_propagation_type(int flags) | ||
| 1491 | { | ||
| 1492 | int type = flags & ~MS_REC; | ||
| 1493 | |||
| 1494 | /* Fail if any non-propagation flags are set */ | ||
| 1495 | if (type & ~(MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) | ||
| 1496 | return 0; | ||
| 1497 | /* Only one propagation flag should be set */ | ||
| 1498 | if (!is_power_of_2(type)) | ||
| 1499 | return 0; | ||
| 1500 | return type; | ||
| 1501 | } | ||
| 1502 | |||
| 1503 | /* | ||
| 1487 | * recursively change the type of the mountpoint. | 1504 | * recursively change the type of the mountpoint. |
| 1488 | */ | 1505 | */ |
| 1489 | static int do_change_type(struct path *path, int flag) | 1506 | static int do_change_type(struct path *path, int flag) |
| 1490 | { | 1507 | { |
| 1491 | struct vfsmount *m, *mnt = path->mnt; | 1508 | struct vfsmount *m, *mnt = path->mnt; |
| 1492 | int recurse = flag & MS_REC; | 1509 | int recurse = flag & MS_REC; |
| 1493 | int type = flag & ~MS_REC; | 1510 | int type; |
| 1494 | int err = 0; | 1511 | int err = 0; |
| 1495 | 1512 | ||
| 1496 | if (!capable(CAP_SYS_ADMIN)) | 1513 | if (!capable(CAP_SYS_ADMIN)) |
| @@ -1499,6 +1516,10 @@ static int do_change_type(struct path *path, int flag) | |||
| 1499 | if (path->dentry != path->mnt->mnt_root) | 1516 | if (path->dentry != path->mnt->mnt_root) |
| 1500 | return -EINVAL; | 1517 | return -EINVAL; |
| 1501 | 1518 | ||
| 1519 | type = flags_to_propagation_type(flag); | ||
| 1520 | if (!type) | ||
| 1521 | return -EINVAL; | ||
| 1522 | |||
| 1502 | down_write(&namespace_sem); | 1523 | down_write(&namespace_sem); |
| 1503 | if (type == MS_SHARED) { | 1524 | if (type == MS_SHARED) { |
| 1504 | err = invent_group_ids(mnt, recurse); | 1525 | err = invent_group_ids(mnt, recurse); |
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index 6c2aad49d731..f7e13db613cb 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig | |||
| @@ -63,6 +63,7 @@ config NFS_V3_ACL | |||
| 63 | config NFS_V4 | 63 | config NFS_V4 |
| 64 | bool "NFS client support for NFS version 4" | 64 | bool "NFS client support for NFS version 4" |
| 65 | depends on NFS_FS | 65 | depends on NFS_FS |
| 66 | select SUNRPC_GSS | ||
| 66 | help | 67 | help |
| 67 | This option enables support for version 4 of the NFS protocol | 68 | This option enables support for version 4 of the NFS protocol |
| 68 | (RFC 3530) in the kernel's NFS client. | 69 | (RFC 3530) in the kernel's NFS client. |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 4e7df2adb212..e7340729af89 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
| @@ -275,7 +275,7 @@ static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1, | |||
| 275 | sin1->sin6_scope_id != sin2->sin6_scope_id) | 275 | sin1->sin6_scope_id != sin2->sin6_scope_id) |
| 276 | return 0; | 276 | return 0; |
| 277 | 277 | ||
| 278 | return ipv6_addr_equal(&sin1->sin6_addr, &sin1->sin6_addr); | 278 | return ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr); |
| 279 | } | 279 | } |
| 280 | #else /* !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE) */ | 280 | #else /* !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE) */ |
| 281 | static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1, | 281 | static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1, |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index eb51bd6201da..05bf3c0dc751 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
| @@ -723,10 +723,6 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl) | |||
| 723 | default: | 723 | default: |
| 724 | BUG(); | 724 | BUG(); |
| 725 | } | 725 | } |
| 726 | if (res < 0) | ||
| 727 | dprintk(KERN_WARNING "%s: VFS is out of sync with lock manager" | ||
| 728 | " - error %d!\n", | ||
| 729 | __func__, res); | ||
| 730 | return res; | 726 | return res; |
| 731 | } | 727 | } |
| 732 | 728 | ||
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index ec3966e4706b..f4cbf0c306c6 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
| @@ -431,7 +431,15 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
| 431 | goto out_err; | 431 | goto out_err; |
| 432 | 432 | ||
| 433 | error = server->nfs_client->rpc_ops->statfs(server, fh, &res); | 433 | error = server->nfs_client->rpc_ops->statfs(server, fh, &res); |
| 434 | if (unlikely(error == -ESTALE)) { | ||
| 435 | struct dentry *pd_dentry; | ||
| 434 | 436 | ||
| 437 | pd_dentry = dget_parent(dentry); | ||
| 438 | if (pd_dentry != NULL) { | ||
| 439 | nfs_zap_caches(pd_dentry->d_inode); | ||
| 440 | dput(pd_dentry); | ||
| 441 | } | ||
| 442 | } | ||
| 435 | nfs_free_fattr(res.fattr); | 443 | nfs_free_fattr(res.fattr); |
| 436 | if (error < 0) | 444 | if (error < 0) |
| 437 | goto out_err; | 445 | goto out_err; |
diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig index 95932f523aef..4264377552e2 100644 --- a/fs/nfsd/Kconfig +++ b/fs/nfsd/Kconfig | |||
| @@ -69,6 +69,7 @@ config NFSD_V4 | |||
| 69 | depends on NFSD && PROC_FS && EXPERIMENTAL | 69 | depends on NFSD && PROC_FS && EXPERIMENTAL |
| 70 | select NFSD_V3 | 70 | select NFSD_V3 |
| 71 | select FS_POSIX_ACL | 71 | select FS_POSIX_ACL |
| 72 | select SUNRPC_GSS | ||
| 72 | help | 73 | help |
| 73 | This option enables support in your system's NFS server for | 74 | This option enables support in your system's NFS server for |
| 74 | version 4 of the NFS protocol (RFC 3530). | 75 | version 4 of the NFS protocol (RFC 3530). |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 3dfef0623968..cf0d2ffb3c84 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
| @@ -440,7 +440,7 @@ test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) { | |||
| 440 | 440 | ||
| 441 | static int nfs4_access_to_omode(u32 access) | 441 | static int nfs4_access_to_omode(u32 access) |
| 442 | { | 442 | { |
| 443 | switch (access) { | 443 | switch (access & NFS4_SHARE_ACCESS_BOTH) { |
| 444 | case NFS4_SHARE_ACCESS_READ: | 444 | case NFS4_SHARE_ACCESS_READ: |
| 445 | return O_RDONLY; | 445 | return O_RDONLY; |
| 446 | case NFS4_SHARE_ACCESS_WRITE: | 446 | case NFS4_SHARE_ACCESS_WRITE: |
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 4317f177ea7c..ba7c10c917fc 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c | |||
| @@ -446,6 +446,7 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
| 446 | nilfs_mdt_destroy(nilfs->ns_cpfile); | 446 | nilfs_mdt_destroy(nilfs->ns_cpfile); |
| 447 | nilfs_mdt_destroy(nilfs->ns_sufile); | 447 | nilfs_mdt_destroy(nilfs->ns_sufile); |
| 448 | nilfs_mdt_destroy(nilfs->ns_dat); | 448 | nilfs_mdt_destroy(nilfs->ns_dat); |
| 449 | nilfs_mdt_destroy(nilfs->ns_gc_dat); | ||
| 449 | 450 | ||
| 450 | failed: | 451 | failed: |
| 451 | nilfs_clear_recovery_info(&ri); | 452 | nilfs_clear_recovery_info(&ri); |
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 215e12ce1d85..592fae5007d1 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c | |||
| @@ -6672,7 +6672,7 @@ int ocfs2_grab_pages(struct inode *inode, loff_t start, loff_t end, | |||
| 6672 | last_page_bytes = PAGE_ALIGN(end); | 6672 | last_page_bytes = PAGE_ALIGN(end); |
| 6673 | index = start >> PAGE_CACHE_SHIFT; | 6673 | index = start >> PAGE_CACHE_SHIFT; |
| 6674 | do { | 6674 | do { |
| 6675 | pages[numpages] = grab_cache_page(mapping, index); | 6675 | pages[numpages] = find_or_create_page(mapping, index, GFP_NOFS); |
| 6676 | if (!pages[numpages]) { | 6676 | if (!pages[numpages]) { |
| 6677 | ret = -ENOMEM; | 6677 | ret = -ENOMEM; |
| 6678 | mlog_errno(ret); | 6678 | mlog_errno(ret); |
diff --git a/fs/ocfs2/blockcheck.c b/fs/ocfs2/blockcheck.c index ec6d12339593..c7ee03c22226 100644 --- a/fs/ocfs2/blockcheck.c +++ b/fs/ocfs2/blockcheck.c | |||
| @@ -439,7 +439,7 @@ int ocfs2_block_check_validate(void *data, size_t blocksize, | |||
| 439 | 439 | ||
| 440 | ocfs2_blockcheck_inc_failure(stats); | 440 | ocfs2_blockcheck_inc_failure(stats); |
| 441 | mlog(ML_ERROR, | 441 | mlog(ML_ERROR, |
| 442 | "CRC32 failed: stored: %u, computed %u. Applying ECC.\n", | 442 | "CRC32 failed: stored: 0x%x, computed 0x%x. Applying ECC.\n", |
| 443 | (unsigned int)check.bc_crc32e, (unsigned int)crc); | 443 | (unsigned int)check.bc_crc32e, (unsigned int)crc); |
| 444 | 444 | ||
| 445 | /* Ok, try ECC fixups */ | 445 | /* Ok, try ECC fixups */ |
| @@ -453,7 +453,7 @@ int ocfs2_block_check_validate(void *data, size_t blocksize, | |||
| 453 | goto out; | 453 | goto out; |
| 454 | } | 454 | } |
| 455 | 455 | ||
| 456 | mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n", | 456 | mlog(ML_ERROR, "Fixed CRC32 failed: stored: 0x%x, computed 0x%x\n", |
| 457 | (unsigned int)check.bc_crc32e, (unsigned int)crc); | 457 | (unsigned int)check.bc_crc32e, (unsigned int)crc); |
| 458 | 458 | ||
| 459 | rc = -EIO; | 459 | rc = -EIO; |
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 81296b4e3646..9a03c151b5ce 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include <linux/writeback.h> | 36 | #include <linux/writeback.h> |
| 37 | #include <linux/falloc.h> | 37 | #include <linux/falloc.h> |
| 38 | #include <linux/quotaops.h> | 38 | #include <linux/quotaops.h> |
| 39 | #include <linux/blkdev.h> | ||
| 39 | 40 | ||
| 40 | #define MLOG_MASK_PREFIX ML_INODE | 41 | #define MLOG_MASK_PREFIX ML_INODE |
| 41 | #include <cluster/masklog.h> | 42 | #include <cluster/masklog.h> |
| @@ -190,8 +191,16 @@ static int ocfs2_sync_file(struct file *file, int datasync) | |||
| 190 | if (err) | 191 | if (err) |
| 191 | goto bail; | 192 | goto bail; |
| 192 | 193 | ||
| 193 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) | 194 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) { |
| 195 | /* | ||
| 196 | * We still have to flush drive's caches to get data to the | ||
| 197 | * platter | ||
| 198 | */ | ||
| 199 | if (osb->s_mount_opt & OCFS2_MOUNT_BARRIER) | ||
| 200 | blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, | ||
| 201 | NULL, BLKDEV_IFL_WAIT); | ||
| 194 | goto bail; | 202 | goto bail; |
| 203 | } | ||
| 195 | 204 | ||
| 196 | journal = osb->journal->j_journal; | 205 | journal = osb->journal->j_journal; |
| 197 | err = jbd2_journal_force_commit(journal); | 206 | err = jbd2_journal_force_commit(journal); |
| @@ -774,7 +783,7 @@ static int ocfs2_write_zero_page(struct inode *inode, u64 abs_from, | |||
| 774 | BUG_ON(abs_to > (((u64)index + 1) << PAGE_CACHE_SHIFT)); | 783 | BUG_ON(abs_to > (((u64)index + 1) << PAGE_CACHE_SHIFT)); |
| 775 | BUG_ON(abs_from & (inode->i_blkbits - 1)); | 784 | BUG_ON(abs_from & (inode->i_blkbits - 1)); |
| 776 | 785 | ||
| 777 | page = grab_cache_page(mapping, index); | 786 | page = find_or_create_page(mapping, index, GFP_NOFS); |
| 778 | if (!page) { | 787 | if (!page) { |
| 779 | ret = -ENOMEM; | 788 | ret = -ENOMEM; |
| 780 | mlog_errno(ret); | 789 | mlog_errno(ret); |
| @@ -2329,7 +2338,7 @@ out_dio: | |||
| 2329 | BUG_ON(ret == -EIOCBQUEUED && !(file->f_flags & O_DIRECT)); | 2338 | BUG_ON(ret == -EIOCBQUEUED && !(file->f_flags & O_DIRECT)); |
| 2330 | 2339 | ||
| 2331 | if (((file->f_flags & O_DSYNC) && !direct_io) || IS_SYNC(inode) || | 2340 | if (((file->f_flags & O_DSYNC) && !direct_io) || IS_SYNC(inode) || |
| 2332 | ((file->f_flags & O_DIRECT) && has_refcount)) { | 2341 | ((file->f_flags & O_DIRECT) && !direct_io)) { |
| 2333 | ret = filemap_fdatawrite_range(file->f_mapping, pos, | 2342 | ret = filemap_fdatawrite_range(file->f_mapping, pos, |
| 2334 | pos + count - 1); | 2343 | pos + count - 1); |
| 2335 | if (ret < 0) | 2344 | if (ret < 0) |
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 0492464916b1..eece3e05d9d0 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c | |||
| @@ -488,7 +488,11 @@ static int ocfs2_read_locked_inode(struct inode *inode, | |||
| 488 | OCFS2_BH_IGNORE_CACHE); | 488 | OCFS2_BH_IGNORE_CACHE); |
| 489 | } else { | 489 | } else { |
| 490 | status = ocfs2_read_blocks_sync(osb, args->fi_blkno, 1, &bh); | 490 | status = ocfs2_read_blocks_sync(osb, args->fi_blkno, 1, &bh); |
| 491 | if (!status) | 491 | /* |
| 492 | * If buffer is in jbd, then its checksum may not have been | ||
| 493 | * computed as yet. | ||
| 494 | */ | ||
| 495 | if (!status && !buffer_jbd(bh)) | ||
| 492 | status = ocfs2_validate_inode_block(osb->sb, bh); | 496 | status = ocfs2_validate_inode_block(osb->sb, bh); |
| 493 | } | 497 | } |
| 494 | if (status < 0) { | 498 | if (status < 0) { |
diff --git a/fs/ocfs2/mmap.c b/fs/ocfs2/mmap.c index af2b8fe1f139..4c18f4ad93b4 100644 --- a/fs/ocfs2/mmap.c +++ b/fs/ocfs2/mmap.c | |||
| @@ -74,9 +74,11 @@ static int __ocfs2_page_mkwrite(struct inode *inode, struct buffer_head *di_bh, | |||
| 74 | /* | 74 | /* |
| 75 | * Another node might have truncated while we were waiting on | 75 | * Another node might have truncated while we were waiting on |
| 76 | * cluster locks. | 76 | * cluster locks. |
| 77 | * We don't check size == 0 before the shift. This is borrowed | ||
| 78 | * from do_generic_file_read. | ||
| 77 | */ | 79 | */ |
| 78 | last_index = size >> PAGE_CACHE_SHIFT; | 80 | last_index = (size - 1) >> PAGE_CACHE_SHIFT; |
| 79 | if (page->index > last_index) { | 81 | if (unlikely(!size || page->index > last_index)) { |
| 80 | ret = -EINVAL; | 82 | ret = -EINVAL; |
| 81 | goto out; | 83 | goto out; |
| 82 | } | 84 | } |
| @@ -107,7 +109,7 @@ static int __ocfs2_page_mkwrite(struct inode *inode, struct buffer_head *di_bh, | |||
| 107 | * because the "write" would invalidate their data. | 109 | * because the "write" would invalidate their data. |
| 108 | */ | 110 | */ |
| 109 | if (page->index == last_index) | 111 | if (page->index == last_index) |
| 110 | len = size & ~PAGE_CACHE_MASK; | 112 | len = ((size - 1) & ~PAGE_CACHE_MASK) + 1; |
| 111 | 113 | ||
| 112 | ret = ocfs2_write_begin_nolock(mapping, pos, len, 0, &locked_page, | 114 | ret = ocfs2_write_begin_nolock(mapping, pos, len, 0, &locked_page, |
| 113 | &fsdata, di_bh, page); | 115 | &fsdata, di_bh, page); |
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index f171b51a74f7..a00dda2e4f16 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c | |||
| @@ -472,32 +472,23 @@ leave: | |||
| 472 | return status; | 472 | return status; |
| 473 | } | 473 | } |
| 474 | 474 | ||
| 475 | static int ocfs2_mknod_locked(struct ocfs2_super *osb, | 475 | static int __ocfs2_mknod_locked(struct inode *dir, |
| 476 | struct inode *dir, | 476 | struct inode *inode, |
| 477 | struct inode *inode, | 477 | dev_t dev, |
| 478 | dev_t dev, | 478 | struct buffer_head **new_fe_bh, |
| 479 | struct buffer_head **new_fe_bh, | 479 | struct buffer_head *parent_fe_bh, |
| 480 | struct buffer_head *parent_fe_bh, | 480 | handle_t *handle, |
| 481 | handle_t *handle, | 481 | struct ocfs2_alloc_context *inode_ac, |
| 482 | struct ocfs2_alloc_context *inode_ac) | 482 | u64 fe_blkno, u64 suballoc_loc, u16 suballoc_bit) |
| 483 | { | 483 | { |
| 484 | int status = 0; | 484 | int status = 0; |
| 485 | struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); | ||
| 485 | struct ocfs2_dinode *fe = NULL; | 486 | struct ocfs2_dinode *fe = NULL; |
| 486 | struct ocfs2_extent_list *fel; | 487 | struct ocfs2_extent_list *fel; |
| 487 | u64 suballoc_loc, fe_blkno = 0; | ||
| 488 | u16 suballoc_bit; | ||
| 489 | u16 feat; | 488 | u16 feat; |
| 490 | 489 | ||
| 491 | *new_fe_bh = NULL; | 490 | *new_fe_bh = NULL; |
| 492 | 491 | ||
| 493 | status = ocfs2_claim_new_inode(handle, dir, parent_fe_bh, | ||
| 494 | inode_ac, &suballoc_loc, | ||
| 495 | &suballoc_bit, &fe_blkno); | ||
| 496 | if (status < 0) { | ||
| 497 | mlog_errno(status); | ||
| 498 | goto leave; | ||
| 499 | } | ||
| 500 | |||
| 501 | /* populate as many fields early on as possible - many of | 492 | /* populate as many fields early on as possible - many of |
| 502 | * these are used by the support functions here and in | 493 | * these are used by the support functions here and in |
| 503 | * callers. */ | 494 | * callers. */ |
| @@ -591,6 +582,34 @@ leave: | |||
| 591 | return status; | 582 | return status; |
| 592 | } | 583 | } |
| 593 | 584 | ||
| 585 | static int ocfs2_mknod_locked(struct ocfs2_super *osb, | ||
| 586 | struct inode *dir, | ||
| 587 | struct inode *inode, | ||
| 588 | dev_t dev, | ||
| 589 | struct buffer_head **new_fe_bh, | ||
| 590 | struct buffer_head *parent_fe_bh, | ||
| 591 | handle_t *handle, | ||
| 592 | struct ocfs2_alloc_context *inode_ac) | ||
| 593 | { | ||
| 594 | int status = 0; | ||
| 595 | u64 suballoc_loc, fe_blkno = 0; | ||
| 596 | u16 suballoc_bit; | ||
| 597 | |||
| 598 | *new_fe_bh = NULL; | ||
| 599 | |||
| 600 | status = ocfs2_claim_new_inode(handle, dir, parent_fe_bh, | ||
| 601 | inode_ac, &suballoc_loc, | ||
| 602 | &suballoc_bit, &fe_blkno); | ||
| 603 | if (status < 0) { | ||
| 604 | mlog_errno(status); | ||
| 605 | return status; | ||
| 606 | } | ||
| 607 | |||
| 608 | return __ocfs2_mknod_locked(dir, inode, dev, new_fe_bh, | ||
| 609 | parent_fe_bh, handle, inode_ac, | ||
| 610 | fe_blkno, suballoc_loc, suballoc_bit); | ||
| 611 | } | ||
| 612 | |||
| 594 | static int ocfs2_mkdir(struct inode *dir, | 613 | static int ocfs2_mkdir(struct inode *dir, |
| 595 | struct dentry *dentry, | 614 | struct dentry *dentry, |
| 596 | int mode) | 615 | int mode) |
| @@ -1852,61 +1871,117 @@ bail: | |||
| 1852 | return status; | 1871 | return status; |
| 1853 | } | 1872 | } |
| 1854 | 1873 | ||
| 1855 | static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb, | 1874 | static int ocfs2_lookup_lock_orphan_dir(struct ocfs2_super *osb, |
| 1856 | struct inode **ret_orphan_dir, | 1875 | struct inode **ret_orphan_dir, |
| 1857 | u64 blkno, | 1876 | struct buffer_head **ret_orphan_dir_bh) |
| 1858 | char *name, | ||
| 1859 | struct ocfs2_dir_lookup_result *lookup) | ||
| 1860 | { | 1877 | { |
| 1861 | struct inode *orphan_dir_inode; | 1878 | struct inode *orphan_dir_inode; |
| 1862 | struct buffer_head *orphan_dir_bh = NULL; | 1879 | struct buffer_head *orphan_dir_bh = NULL; |
| 1863 | int status = 0; | 1880 | int ret = 0; |
| 1864 | |||
| 1865 | status = ocfs2_blkno_stringify(blkno, name); | ||
| 1866 | if (status < 0) { | ||
| 1867 | mlog_errno(status); | ||
| 1868 | return status; | ||
| 1869 | } | ||
| 1870 | 1881 | ||
| 1871 | orphan_dir_inode = ocfs2_get_system_file_inode(osb, | 1882 | orphan_dir_inode = ocfs2_get_system_file_inode(osb, |
| 1872 | ORPHAN_DIR_SYSTEM_INODE, | 1883 | ORPHAN_DIR_SYSTEM_INODE, |
| 1873 | osb->slot_num); | 1884 | osb->slot_num); |
| 1874 | if (!orphan_dir_inode) { | 1885 | if (!orphan_dir_inode) { |
| 1875 | status = -ENOENT; | 1886 | ret = -ENOENT; |
| 1876 | mlog_errno(status); | 1887 | mlog_errno(ret); |
| 1877 | return status; | 1888 | return ret; |
| 1878 | } | 1889 | } |
| 1879 | 1890 | ||
| 1880 | mutex_lock(&orphan_dir_inode->i_mutex); | 1891 | mutex_lock(&orphan_dir_inode->i_mutex); |
| 1881 | 1892 | ||
| 1882 | status = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1); | 1893 | ret = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1); |
| 1883 | if (status < 0) { | 1894 | if (ret < 0) { |
| 1884 | mlog_errno(status); | 1895 | mutex_unlock(&orphan_dir_inode->i_mutex); |
| 1885 | goto leave; | 1896 | iput(orphan_dir_inode); |
| 1897 | |||
| 1898 | mlog_errno(ret); | ||
| 1899 | return ret; | ||
| 1886 | } | 1900 | } |
| 1887 | 1901 | ||
| 1888 | status = ocfs2_prepare_dir_for_insert(osb, orphan_dir_inode, | 1902 | *ret_orphan_dir = orphan_dir_inode; |
| 1889 | orphan_dir_bh, name, | 1903 | *ret_orphan_dir_bh = orphan_dir_bh; |
| 1890 | OCFS2_ORPHAN_NAMELEN, lookup); | ||
| 1891 | if (status < 0) { | ||
| 1892 | ocfs2_inode_unlock(orphan_dir_inode, 1); | ||
| 1893 | 1904 | ||
| 1894 | mlog_errno(status); | 1905 | return 0; |
| 1895 | goto leave; | 1906 | } |
| 1907 | |||
| 1908 | static int __ocfs2_prepare_orphan_dir(struct inode *orphan_dir_inode, | ||
| 1909 | struct buffer_head *orphan_dir_bh, | ||
| 1910 | u64 blkno, | ||
| 1911 | char *name, | ||
| 1912 | struct ocfs2_dir_lookup_result *lookup) | ||
| 1913 | { | ||
| 1914 | int ret; | ||
| 1915 | struct ocfs2_super *osb = OCFS2_SB(orphan_dir_inode->i_sb); | ||
| 1916 | |||
| 1917 | ret = ocfs2_blkno_stringify(blkno, name); | ||
| 1918 | if (ret < 0) { | ||
| 1919 | mlog_errno(ret); | ||
| 1920 | return ret; | ||
| 1921 | } | ||
| 1922 | |||
| 1923 | ret = ocfs2_prepare_dir_for_insert(osb, orphan_dir_inode, | ||
| 1924 | orphan_dir_bh, name, | ||
| 1925 | OCFS2_ORPHAN_NAMELEN, lookup); | ||
| 1926 | if (ret < 0) { | ||
| 1927 | mlog_errno(ret); | ||
| 1928 | return ret; | ||
| 1929 | } | ||
| 1930 | |||
| 1931 | return 0; | ||
| 1932 | } | ||
| 1933 | |||
| 1934 | /** | ||
| 1935 | * ocfs2_prepare_orphan_dir() - Prepare an orphan directory for | ||
| 1936 | * insertion of an orphan. | ||
| 1937 | * @osb: ocfs2 file system | ||
| 1938 | * @ret_orphan_dir: Orphan dir inode - returned locked! | ||
| 1939 | * @blkno: Actual block number of the inode to be inserted into orphan dir. | ||
| 1940 | * @lookup: dir lookup result, to be passed back into functions like | ||
| 1941 | * ocfs2_orphan_add | ||
| 1942 | * | ||
| 1943 | * Returns zero on success and the ret_orphan_dir, name and lookup | ||
| 1944 | * fields will be populated. | ||
| 1945 | * | ||
| 1946 | * Returns non-zero on failure. | ||
| 1947 | */ | ||
| 1948 | static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb, | ||
| 1949 | struct inode **ret_orphan_dir, | ||
| 1950 | u64 blkno, | ||
| 1951 | char *name, | ||
| 1952 | struct ocfs2_dir_lookup_result *lookup) | ||
| 1953 | { | ||
| 1954 | struct inode *orphan_dir_inode = NULL; | ||
| 1955 | struct buffer_head *orphan_dir_bh = NULL; | ||
| 1956 | int ret = 0; | ||
| 1957 | |||
| 1958 | ret = ocfs2_lookup_lock_orphan_dir(osb, &orphan_dir_inode, | ||
| 1959 | &orphan_dir_bh); | ||
| 1960 | if (ret < 0) { | ||
| 1961 | mlog_errno(ret); | ||
| 1962 | return ret; | ||
| 1963 | } | ||
| 1964 | |||
| 1965 | ret = __ocfs2_prepare_orphan_dir(orphan_dir_inode, orphan_dir_bh, | ||
| 1966 | blkno, name, lookup); | ||
| 1967 | if (ret < 0) { | ||
| 1968 | mlog_errno(ret); | ||
| 1969 | goto out; | ||
| 1896 | } | 1970 | } |
| 1897 | 1971 | ||
| 1898 | *ret_orphan_dir = orphan_dir_inode; | 1972 | *ret_orphan_dir = orphan_dir_inode; |
| 1899 | 1973 | ||
| 1900 | leave: | 1974 | out: |
| 1901 | if (status) { | 1975 | brelse(orphan_dir_bh); |
| 1976 | |||
| 1977 | if (ret) { | ||
| 1978 | ocfs2_inode_unlock(orphan_dir_inode, 1); | ||
| 1902 | mutex_unlock(&orphan_dir_inode->i_mutex); | 1979 | mutex_unlock(&orphan_dir_inode->i_mutex); |
| 1903 | iput(orphan_dir_inode); | 1980 | iput(orphan_dir_inode); |
| 1904 | } | 1981 | } |
| 1905 | 1982 | ||
| 1906 | brelse(orphan_dir_bh); | 1983 | mlog_exit(ret); |
| 1907 | 1984 | return ret; | |
| 1908 | mlog_exit(status); | ||
| 1909 | return status; | ||
| 1910 | } | 1985 | } |
| 1911 | 1986 | ||
| 1912 | static int ocfs2_orphan_add(struct ocfs2_super *osb, | 1987 | static int ocfs2_orphan_add(struct ocfs2_super *osb, |
| @@ -2053,6 +2128,99 @@ leave: | |||
| 2053 | return status; | 2128 | return status; |
| 2054 | } | 2129 | } |
| 2055 | 2130 | ||
| 2131 | /** | ||
| 2132 | * ocfs2_prep_new_orphaned_file() - Prepare the orphan dir to recieve a newly | ||
| 2133 | * allocated file. This is different from the typical 'add to orphan dir' | ||
| 2134 | * operation in that the inode does not yet exist. This is a problem because | ||
| 2135 | * the orphan dir stringifies the inode block number to come up with it's | ||
| 2136 | * dirent. Obviously if the inode does not yet exist we have a chicken and egg | ||
| 2137 | * problem. This function works around it by calling deeper into the orphan | ||
| 2138 | * and suballoc code than other callers. Use this only by necessity. | ||
| 2139 | * @dir: The directory which this inode will ultimately wind up under - not the | ||
| 2140 | * orphan dir! | ||
| 2141 | * @dir_bh: buffer_head the @dir inode block | ||
| 2142 | * @orphan_name: string of length (CFS2_ORPHAN_NAMELEN + 1). Will be filled | ||
| 2143 | * with the string to be used for orphan dirent. Pass back to the orphan dir | ||
| 2144 | * code. | ||
| 2145 | * @ret_orphan_dir: orphan dir inode returned to be passed back into orphan | ||
| 2146 | * dir code. | ||
| 2147 | * @ret_di_blkno: block number where the new inode will be allocated. | ||
| 2148 | * @orphan_insert: Dir insert context to be passed back into orphan dir code. | ||
| 2149 | * @ret_inode_ac: Inode alloc context to be passed back to the allocator. | ||
| 2150 | * | ||
| 2151 | * Returns zero on success and the ret_orphan_dir, name and lookup | ||
| 2152 | * fields will be populated. | ||
| 2153 | * | ||
| 2154 | * Returns non-zero on failure. | ||
| 2155 | */ | ||
| 2156 | static int ocfs2_prep_new_orphaned_file(struct inode *dir, | ||
| 2157 | struct buffer_head *dir_bh, | ||
| 2158 | char *orphan_name, | ||
| 2159 | struct inode **ret_orphan_dir, | ||
| 2160 | u64 *ret_di_blkno, | ||
| 2161 | struct ocfs2_dir_lookup_result *orphan_insert, | ||
| 2162 | struct ocfs2_alloc_context **ret_inode_ac) | ||
| 2163 | { | ||
| 2164 | int ret; | ||
| 2165 | u64 di_blkno; | ||
| 2166 | struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); | ||
| 2167 | struct inode *orphan_dir = NULL; | ||
| 2168 | struct buffer_head *orphan_dir_bh = NULL; | ||
| 2169 | struct ocfs2_alloc_context *inode_ac = NULL; | ||
| 2170 | |||
| 2171 | ret = ocfs2_lookup_lock_orphan_dir(osb, &orphan_dir, &orphan_dir_bh); | ||
| 2172 | if (ret < 0) { | ||
| 2173 | mlog_errno(ret); | ||
| 2174 | return ret; | ||
| 2175 | } | ||
| 2176 | |||
| 2177 | /* reserve an inode spot */ | ||
| 2178 | ret = ocfs2_reserve_new_inode(osb, &inode_ac); | ||
| 2179 | if (ret < 0) { | ||
| 2180 | if (ret != -ENOSPC) | ||
| 2181 | mlog_errno(ret); | ||
| 2182 | goto out; | ||
| 2183 | } | ||
| 2184 | |||
| 2185 | ret = ocfs2_find_new_inode_loc(dir, dir_bh, inode_ac, | ||
| 2186 | &di_blkno); | ||
| 2187 | if (ret) { | ||
| 2188 | mlog_errno(ret); | ||
| 2189 | goto out; | ||
| 2190 | } | ||
| 2191 | |||
| 2192 | ret = __ocfs2_prepare_orphan_dir(orphan_dir, orphan_dir_bh, | ||
| 2193 | di_blkno, orphan_name, orphan_insert); | ||
| 2194 | if (ret < 0) { | ||
| 2195 | mlog_errno(ret); | ||
| 2196 | goto out; | ||
| 2197 | } | ||
| 2198 | |||
| 2199 | out: | ||
| 2200 | if (ret == 0) { | ||
| 2201 | *ret_orphan_dir = orphan_dir; | ||
| 2202 | *ret_di_blkno = di_blkno; | ||
| 2203 | *ret_inode_ac = inode_ac; | ||
| 2204 | /* | ||
| 2205 | * orphan_name and orphan_insert are already up to | ||
| 2206 | * date via prepare_orphan_dir | ||
| 2207 | */ | ||
| 2208 | } else { | ||
| 2209 | /* Unroll reserve_new_inode* */ | ||
| 2210 | if (inode_ac) | ||
| 2211 | ocfs2_free_alloc_context(inode_ac); | ||
| 2212 | |||
| 2213 | /* Unroll orphan dir locking */ | ||
| 2214 | mutex_unlock(&orphan_dir->i_mutex); | ||
| 2215 | ocfs2_inode_unlock(orphan_dir, 1); | ||
| 2216 | iput(orphan_dir); | ||
| 2217 | } | ||
| 2218 | |||
| 2219 | brelse(orphan_dir_bh); | ||
| 2220 | |||
| 2221 | return 0; | ||
| 2222 | } | ||
| 2223 | |||
| 2056 | int ocfs2_create_inode_in_orphan(struct inode *dir, | 2224 | int ocfs2_create_inode_in_orphan(struct inode *dir, |
| 2057 | int mode, | 2225 | int mode, |
| 2058 | struct inode **new_inode) | 2226 | struct inode **new_inode) |
| @@ -2068,6 +2236,8 @@ int ocfs2_create_inode_in_orphan(struct inode *dir, | |||
| 2068 | struct buffer_head *new_di_bh = NULL; | 2236 | struct buffer_head *new_di_bh = NULL; |
| 2069 | struct ocfs2_alloc_context *inode_ac = NULL; | 2237 | struct ocfs2_alloc_context *inode_ac = NULL; |
| 2070 | struct ocfs2_dir_lookup_result orphan_insert = { NULL, }; | 2238 | struct ocfs2_dir_lookup_result orphan_insert = { NULL, }; |
| 2239 | u64 uninitialized_var(di_blkno), suballoc_loc; | ||
| 2240 | u16 suballoc_bit; | ||
| 2071 | 2241 | ||
| 2072 | status = ocfs2_inode_lock(dir, &parent_di_bh, 1); | 2242 | status = ocfs2_inode_lock(dir, &parent_di_bh, 1); |
| 2073 | if (status < 0) { | 2243 | if (status < 0) { |
| @@ -2076,20 +2246,9 @@ int ocfs2_create_inode_in_orphan(struct inode *dir, | |||
| 2076 | return status; | 2246 | return status; |
| 2077 | } | 2247 | } |
| 2078 | 2248 | ||
| 2079 | /* | 2249 | status = ocfs2_prep_new_orphaned_file(dir, parent_di_bh, |
| 2080 | * We give the orphan dir the root blkno to fake an orphan name, | 2250 | orphan_name, &orphan_dir, |
| 2081 | * and allocate enough space for our insertion. | 2251 | &di_blkno, &orphan_insert, &inode_ac); |
| 2082 | */ | ||
| 2083 | status = ocfs2_prepare_orphan_dir(osb, &orphan_dir, | ||
| 2084 | osb->root_blkno, | ||
| 2085 | orphan_name, &orphan_insert); | ||
| 2086 | if (status < 0) { | ||
| 2087 | mlog_errno(status); | ||
| 2088 | goto leave; | ||
| 2089 | } | ||
| 2090 | |||
| 2091 | /* reserve an inode spot */ | ||
| 2092 | status = ocfs2_reserve_new_inode(osb, &inode_ac); | ||
| 2093 | if (status < 0) { | 2252 | if (status < 0) { |
| 2094 | if (status != -ENOSPC) | 2253 | if (status != -ENOSPC) |
| 2095 | mlog_errno(status); | 2254 | mlog_errno(status); |
| @@ -2116,17 +2275,20 @@ int ocfs2_create_inode_in_orphan(struct inode *dir, | |||
| 2116 | goto leave; | 2275 | goto leave; |
| 2117 | did_quota_inode = 1; | 2276 | did_quota_inode = 1; |
| 2118 | 2277 | ||
| 2119 | inode->i_nlink = 0; | 2278 | status = ocfs2_claim_new_inode_at_loc(handle, dir, inode_ac, |
| 2120 | /* do the real work now. */ | 2279 | &suballoc_loc, |
| 2121 | status = ocfs2_mknod_locked(osb, dir, inode, | 2280 | &suballoc_bit, di_blkno); |
| 2122 | 0, &new_di_bh, parent_di_bh, handle, | ||
| 2123 | inode_ac); | ||
| 2124 | if (status < 0) { | 2281 | if (status < 0) { |
| 2125 | mlog_errno(status); | 2282 | mlog_errno(status); |
| 2126 | goto leave; | 2283 | goto leave; |
| 2127 | } | 2284 | } |
| 2128 | 2285 | ||
| 2129 | status = ocfs2_blkno_stringify(OCFS2_I(inode)->ip_blkno, orphan_name); | 2286 | inode->i_nlink = 0; |
| 2287 | /* do the real work now. */ | ||
| 2288 | status = __ocfs2_mknod_locked(dir, inode, | ||
| 2289 | 0, &new_di_bh, parent_di_bh, handle, | ||
| 2290 | inode_ac, di_blkno, suballoc_loc, | ||
| 2291 | suballoc_bit); | ||
| 2130 | if (status < 0) { | 2292 | if (status < 0) { |
| 2131 | mlog_errno(status); | 2293 | mlog_errno(status); |
| 2132 | goto leave; | 2294 | goto leave; |
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 73a11ccfd4c2..0afeda83120f 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c | |||
| @@ -2960,7 +2960,7 @@ static int ocfs2_duplicate_clusters_by_page(handle_t *handle, | |||
| 2960 | if (map_end & (PAGE_CACHE_SIZE - 1)) | 2960 | if (map_end & (PAGE_CACHE_SIZE - 1)) |
| 2961 | to = map_end & (PAGE_CACHE_SIZE - 1); | 2961 | to = map_end & (PAGE_CACHE_SIZE - 1); |
| 2962 | 2962 | ||
| 2963 | page = grab_cache_page(mapping, page_index); | 2963 | page = find_or_create_page(mapping, page_index, GFP_NOFS); |
| 2964 | 2964 | ||
| 2965 | /* | 2965 | /* |
| 2966 | * In case PAGE_CACHE_SIZE <= CLUSTER_SIZE, This page | 2966 | * In case PAGE_CACHE_SIZE <= CLUSTER_SIZE, This page |
| @@ -3179,7 +3179,8 @@ static int ocfs2_cow_sync_writeback(struct super_block *sb, | |||
| 3179 | if (map_end > end) | 3179 | if (map_end > end) |
| 3180 | map_end = end; | 3180 | map_end = end; |
| 3181 | 3181 | ||
| 3182 | page = grab_cache_page(context->inode->i_mapping, page_index); | 3182 | page = find_or_create_page(context->inode->i_mapping, |
| 3183 | page_index, GFP_NOFS); | ||
| 3183 | BUG_ON(!page); | 3184 | BUG_ON(!page); |
| 3184 | 3185 | ||
| 3185 | wait_on_page_writeback(page); | 3186 | wait_on_page_writeback(page); |
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index a8e6a95a353f..8a286f54dca1 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c | |||
| @@ -57,11 +57,28 @@ struct ocfs2_suballoc_result { | |||
| 57 | u64 sr_bg_blkno; /* The bg we allocated from. Set | 57 | u64 sr_bg_blkno; /* The bg we allocated from. Set |
| 58 | to 0 when a block group is | 58 | to 0 when a block group is |
| 59 | contiguous. */ | 59 | contiguous. */ |
| 60 | u64 sr_bg_stable_blkno; /* | ||
| 61 | * Doesn't change, always | ||
| 62 | * set to target block | ||
| 63 | * group descriptor | ||
| 64 | * block. | ||
| 65 | */ | ||
| 60 | u64 sr_blkno; /* The first allocated block */ | 66 | u64 sr_blkno; /* The first allocated block */ |
| 61 | unsigned int sr_bit_offset; /* The bit in the bg */ | 67 | unsigned int sr_bit_offset; /* The bit in the bg */ |
| 62 | unsigned int sr_bits; /* How many bits we claimed */ | 68 | unsigned int sr_bits; /* How many bits we claimed */ |
| 63 | }; | 69 | }; |
| 64 | 70 | ||
| 71 | static u64 ocfs2_group_from_res(struct ocfs2_suballoc_result *res) | ||
| 72 | { | ||
| 73 | if (res->sr_blkno == 0) | ||
| 74 | return 0; | ||
| 75 | |||
| 76 | if (res->sr_bg_blkno) | ||
| 77 | return res->sr_bg_blkno; | ||
| 78 | |||
| 79 | return ocfs2_which_suballoc_group(res->sr_blkno, res->sr_bit_offset); | ||
| 80 | } | ||
| 81 | |||
| 65 | static inline void ocfs2_debug_bg(struct ocfs2_group_desc *bg); | 82 | static inline void ocfs2_debug_bg(struct ocfs2_group_desc *bg); |
| 66 | static inline void ocfs2_debug_suballoc_inode(struct ocfs2_dinode *fe); | 83 | static inline void ocfs2_debug_suballoc_inode(struct ocfs2_dinode *fe); |
| 67 | static inline u16 ocfs2_find_victim_chain(struct ocfs2_chain_list *cl); | 84 | static inline u16 ocfs2_find_victim_chain(struct ocfs2_chain_list *cl); |
| @@ -138,6 +155,10 @@ void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac) | |||
| 138 | brelse(ac->ac_bh); | 155 | brelse(ac->ac_bh); |
| 139 | ac->ac_bh = NULL; | 156 | ac->ac_bh = NULL; |
| 140 | ac->ac_resv = NULL; | 157 | ac->ac_resv = NULL; |
| 158 | if (ac->ac_find_loc_priv) { | ||
| 159 | kfree(ac->ac_find_loc_priv); | ||
| 160 | ac->ac_find_loc_priv = NULL; | ||
| 161 | } | ||
| 141 | } | 162 | } |
| 142 | 163 | ||
| 143 | void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac) | 164 | void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac) |
| @@ -1678,6 +1699,15 @@ static int ocfs2_search_one_group(struct ocfs2_alloc_context *ac, | |||
| 1678 | if (!ret) | 1699 | if (!ret) |
| 1679 | ocfs2_bg_discontig_fix_result(ac, gd, res); | 1700 | ocfs2_bg_discontig_fix_result(ac, gd, res); |
| 1680 | 1701 | ||
| 1702 | /* | ||
| 1703 | * sr_bg_blkno might have been changed by | ||
| 1704 | * ocfs2_bg_discontig_fix_result | ||
| 1705 | */ | ||
| 1706 | res->sr_bg_stable_blkno = group_bh->b_blocknr; | ||
| 1707 | |||
| 1708 | if (ac->ac_find_loc_only) | ||
| 1709 | goto out_loc_only; | ||
| 1710 | |||
| 1681 | ret = ocfs2_alloc_dinode_update_counts(alloc_inode, handle, ac->ac_bh, | 1711 | ret = ocfs2_alloc_dinode_update_counts(alloc_inode, handle, ac->ac_bh, |
| 1682 | res->sr_bits, | 1712 | res->sr_bits, |
| 1683 | le16_to_cpu(gd->bg_chain)); | 1713 | le16_to_cpu(gd->bg_chain)); |
| @@ -1691,6 +1721,7 @@ static int ocfs2_search_one_group(struct ocfs2_alloc_context *ac, | |||
| 1691 | if (ret < 0) | 1721 | if (ret < 0) |
| 1692 | mlog_errno(ret); | 1722 | mlog_errno(ret); |
| 1693 | 1723 | ||
| 1724 | out_loc_only: | ||
| 1694 | *bits_left = le16_to_cpu(gd->bg_free_bits_count); | 1725 | *bits_left = le16_to_cpu(gd->bg_free_bits_count); |
| 1695 | 1726 | ||
| 1696 | out: | 1727 | out: |
| @@ -1708,7 +1739,6 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, | |||
| 1708 | { | 1739 | { |
| 1709 | int status; | 1740 | int status; |
| 1710 | u16 chain; | 1741 | u16 chain; |
| 1711 | u32 tmp_used; | ||
| 1712 | u64 next_group; | 1742 | u64 next_group; |
| 1713 | struct inode *alloc_inode = ac->ac_inode; | 1743 | struct inode *alloc_inode = ac->ac_inode; |
| 1714 | struct buffer_head *group_bh = NULL; | 1744 | struct buffer_head *group_bh = NULL; |
| @@ -1770,6 +1800,11 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, | |||
| 1770 | if (!status) | 1800 | if (!status) |
| 1771 | ocfs2_bg_discontig_fix_result(ac, bg, res); | 1801 | ocfs2_bg_discontig_fix_result(ac, bg, res); |
| 1772 | 1802 | ||
| 1803 | /* | ||
| 1804 | * sr_bg_blkno might have been changed by | ||
| 1805 | * ocfs2_bg_discontig_fix_result | ||
| 1806 | */ | ||
| 1807 | res->sr_bg_stable_blkno = group_bh->b_blocknr; | ||
| 1773 | 1808 | ||
| 1774 | /* | 1809 | /* |
| 1775 | * Keep track of previous block descriptor read. When | 1810 | * Keep track of previous block descriptor read. When |
| @@ -1796,22 +1831,17 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, | |||
| 1796 | } | 1831 | } |
| 1797 | } | 1832 | } |
| 1798 | 1833 | ||
| 1799 | /* Ok, claim our bits now: set the info on dinode, chainlist | 1834 | if (ac->ac_find_loc_only) |
| 1800 | * and then the group */ | 1835 | goto out_loc_only; |
| 1801 | status = ocfs2_journal_access_di(handle, | 1836 | |
| 1802 | INODE_CACHE(alloc_inode), | 1837 | status = ocfs2_alloc_dinode_update_counts(alloc_inode, handle, |
| 1803 | ac->ac_bh, | 1838 | ac->ac_bh, res->sr_bits, |
| 1804 | OCFS2_JOURNAL_ACCESS_WRITE); | 1839 | chain); |
| 1805 | if (status < 0) { | 1840 | if (status) { |
| 1806 | mlog_errno(status); | 1841 | mlog_errno(status); |
| 1807 | goto bail; | 1842 | goto bail; |
| 1808 | } | 1843 | } |
| 1809 | 1844 | ||
| 1810 | tmp_used = le32_to_cpu(fe->id1.bitmap1.i_used); | ||
| 1811 | fe->id1.bitmap1.i_used = cpu_to_le32(res->sr_bits + tmp_used); | ||
| 1812 | le32_add_cpu(&cl->cl_recs[chain].c_free, -res->sr_bits); | ||
| 1813 | ocfs2_journal_dirty(handle, ac->ac_bh); | ||
| 1814 | |||
| 1815 | status = ocfs2_block_group_set_bits(handle, | 1845 | status = ocfs2_block_group_set_bits(handle, |
| 1816 | alloc_inode, | 1846 | alloc_inode, |
| 1817 | bg, | 1847 | bg, |
| @@ -1826,6 +1856,7 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, | |||
| 1826 | mlog(0, "Allocated %u bits from suballocator %llu\n", res->sr_bits, | 1856 | mlog(0, "Allocated %u bits from suballocator %llu\n", res->sr_bits, |
| 1827 | (unsigned long long)le64_to_cpu(fe->i_blkno)); | 1857 | (unsigned long long)le64_to_cpu(fe->i_blkno)); |
| 1828 | 1858 | ||
| 1859 | out_loc_only: | ||
| 1829 | *bits_left = le16_to_cpu(bg->bg_free_bits_count); | 1860 | *bits_left = le16_to_cpu(bg->bg_free_bits_count); |
| 1830 | bail: | 1861 | bail: |
| 1831 | brelse(group_bh); | 1862 | brelse(group_bh); |
| @@ -1845,6 +1876,7 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, | |||
| 1845 | int status; | 1876 | int status; |
| 1846 | u16 victim, i; | 1877 | u16 victim, i; |
| 1847 | u16 bits_left = 0; | 1878 | u16 bits_left = 0; |
| 1879 | u64 hint = ac->ac_last_group; | ||
| 1848 | struct ocfs2_chain_list *cl; | 1880 | struct ocfs2_chain_list *cl; |
| 1849 | struct ocfs2_dinode *fe; | 1881 | struct ocfs2_dinode *fe; |
| 1850 | 1882 | ||
| @@ -1872,7 +1904,7 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, | |||
| 1872 | goto bail; | 1904 | goto bail; |
| 1873 | } | 1905 | } |
| 1874 | 1906 | ||
| 1875 | res->sr_bg_blkno = ac->ac_last_group; | 1907 | res->sr_bg_blkno = hint; |
| 1876 | if (res->sr_bg_blkno) { | 1908 | if (res->sr_bg_blkno) { |
| 1877 | /* Attempt to short-circuit the usual search mechanism | 1909 | /* Attempt to short-circuit the usual search mechanism |
| 1878 | * by jumping straight to the most recently used | 1910 | * by jumping straight to the most recently used |
| @@ -1896,8 +1928,10 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, | |||
| 1896 | 1928 | ||
| 1897 | status = ocfs2_search_chain(ac, handle, bits_wanted, min_bits, | 1929 | status = ocfs2_search_chain(ac, handle, bits_wanted, min_bits, |
| 1898 | res, &bits_left); | 1930 | res, &bits_left); |
| 1899 | if (!status) | 1931 | if (!status) { |
| 1932 | hint = ocfs2_group_from_res(res); | ||
| 1900 | goto set_hint; | 1933 | goto set_hint; |
| 1934 | } | ||
| 1901 | if (status < 0 && status != -ENOSPC) { | 1935 | if (status < 0 && status != -ENOSPC) { |
| 1902 | mlog_errno(status); | 1936 | mlog_errno(status); |
| 1903 | goto bail; | 1937 | goto bail; |
| @@ -1920,8 +1954,10 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, | |||
| 1920 | ac->ac_chain = i; | 1954 | ac->ac_chain = i; |
| 1921 | status = ocfs2_search_chain(ac, handle, bits_wanted, min_bits, | 1955 | status = ocfs2_search_chain(ac, handle, bits_wanted, min_bits, |
| 1922 | res, &bits_left); | 1956 | res, &bits_left); |
| 1923 | if (!status) | 1957 | if (!status) { |
| 1958 | hint = ocfs2_group_from_res(res); | ||
| 1924 | break; | 1959 | break; |
| 1960 | } | ||
| 1925 | if (status < 0 && status != -ENOSPC) { | 1961 | if (status < 0 && status != -ENOSPC) { |
| 1926 | mlog_errno(status); | 1962 | mlog_errno(status); |
| 1927 | goto bail; | 1963 | goto bail; |
| @@ -1936,7 +1972,7 @@ set_hint: | |||
| 1936 | if (bits_left < min_bits) | 1972 | if (bits_left < min_bits) |
| 1937 | ac->ac_last_group = 0; | 1973 | ac->ac_last_group = 0; |
| 1938 | else | 1974 | else |
| 1939 | ac->ac_last_group = res->sr_bg_blkno; | 1975 | ac->ac_last_group = hint; |
| 1940 | } | 1976 | } |
| 1941 | 1977 | ||
| 1942 | bail: | 1978 | bail: |
| @@ -2016,6 +2052,136 @@ static inline void ocfs2_save_inode_ac_group(struct inode *dir, | |||
| 2016 | OCFS2_I(dir)->ip_last_used_slot = ac->ac_alloc_slot; | 2052 | OCFS2_I(dir)->ip_last_used_slot = ac->ac_alloc_slot; |
| 2017 | } | 2053 | } |
| 2018 | 2054 | ||
| 2055 | int ocfs2_find_new_inode_loc(struct inode *dir, | ||
| 2056 | struct buffer_head *parent_fe_bh, | ||
| 2057 | struct ocfs2_alloc_context *ac, | ||
| 2058 | u64 *fe_blkno) | ||
| 2059 | { | ||
| 2060 | int ret; | ||
| 2061 | handle_t *handle = NULL; | ||
| 2062 | struct ocfs2_suballoc_result *res; | ||
| 2063 | |||
| 2064 | BUG_ON(!ac); | ||
| 2065 | BUG_ON(ac->ac_bits_given != 0); | ||
| 2066 | BUG_ON(ac->ac_bits_wanted != 1); | ||
| 2067 | BUG_ON(ac->ac_which != OCFS2_AC_USE_INODE); | ||
| 2068 | |||
| 2069 | res = kzalloc(sizeof(*res), GFP_NOFS); | ||
| 2070 | if (res == NULL) { | ||
| 2071 | ret = -ENOMEM; | ||
| 2072 | mlog_errno(ret); | ||
| 2073 | goto out; | ||
| 2074 | } | ||
| 2075 | |||
| 2076 | ocfs2_init_inode_ac_group(dir, parent_fe_bh, ac); | ||
| 2077 | |||
| 2078 | /* | ||
| 2079 | * The handle started here is for chain relink. Alternatively, | ||
| 2080 | * we could just disable relink for these calls. | ||
| 2081 | */ | ||
| 2082 | handle = ocfs2_start_trans(OCFS2_SB(dir->i_sb), OCFS2_SUBALLOC_ALLOC); | ||
| 2083 | if (IS_ERR(handle)) { | ||
| 2084 | ret = PTR_ERR(handle); | ||
| 2085 | handle = NULL; | ||
| 2086 | mlog_errno(ret); | ||
| 2087 | goto out; | ||
| 2088 | } | ||
| 2089 | |||
| 2090 | /* | ||
| 2091 | * This will instruct ocfs2_claim_suballoc_bits and | ||
| 2092 | * ocfs2_search_one_group to search but save actual allocation | ||
| 2093 | * for later. | ||
| 2094 | */ | ||
| 2095 | ac->ac_find_loc_only = 1; | ||
| 2096 | |||
| 2097 | ret = ocfs2_claim_suballoc_bits(ac, handle, 1, 1, res); | ||
| 2098 | if (ret < 0) { | ||
| 2099 | mlog_errno(ret); | ||
| 2100 | goto out; | ||
| 2101 | } | ||
| 2102 | |||
| 2103 | ac->ac_find_loc_priv = res; | ||
| 2104 | *fe_blkno = res->sr_blkno; | ||
| 2105 | |||
| 2106 | out: | ||
| 2107 | if (handle) | ||
| 2108 | ocfs2_commit_trans(OCFS2_SB(dir->i_sb), handle); | ||
| 2109 | |||
| 2110 | if (ret) | ||
| 2111 | kfree(res); | ||
| 2112 | |||
| 2113 | return ret; | ||
| 2114 | } | ||
| 2115 | |||
| 2116 | int ocfs2_claim_new_inode_at_loc(handle_t *handle, | ||
| 2117 | struct inode *dir, | ||
| 2118 | struct ocfs2_alloc_context *ac, | ||
| 2119 | u64 *suballoc_loc, | ||
| 2120 | u16 *suballoc_bit, | ||
| 2121 | u64 di_blkno) | ||
| 2122 | { | ||
| 2123 | int ret; | ||
| 2124 | u16 chain; | ||
| 2125 | struct ocfs2_suballoc_result *res = ac->ac_find_loc_priv; | ||
| 2126 | struct buffer_head *bg_bh = NULL; | ||
| 2127 | struct ocfs2_group_desc *bg; | ||
| 2128 | struct ocfs2_dinode *di = (struct ocfs2_dinode *) ac->ac_bh->b_data; | ||
| 2129 | |||
| 2130 | /* | ||
| 2131 | * Since di_blkno is being passed back in, we check for any | ||
| 2132 | * inconsistencies which may have happened between | ||
| 2133 | * calls. These are code bugs as di_blkno is not expected to | ||
| 2134 | * change once returned from ocfs2_find_new_inode_loc() | ||
| 2135 | */ | ||
| 2136 | BUG_ON(res->sr_blkno != di_blkno); | ||
| 2137 | |||
| 2138 | ret = ocfs2_read_group_descriptor(ac->ac_inode, di, | ||
| 2139 | res->sr_bg_stable_blkno, &bg_bh); | ||
| 2140 | if (ret) { | ||
| 2141 | mlog_errno(ret); | ||
| 2142 | goto out; | ||
| 2143 | } | ||
| 2144 | |||
| 2145 | bg = (struct ocfs2_group_desc *) bg_bh->b_data; | ||
| 2146 | chain = le16_to_cpu(bg->bg_chain); | ||
| 2147 | |||
| 2148 | ret = ocfs2_alloc_dinode_update_counts(ac->ac_inode, handle, | ||
| 2149 | ac->ac_bh, res->sr_bits, | ||
| 2150 | chain); | ||
| 2151 | if (ret) { | ||
| 2152 | mlog_errno(ret); | ||
| 2153 | goto out; | ||
| 2154 | } | ||
| 2155 | |||
| 2156 | ret = ocfs2_block_group_set_bits(handle, | ||
| 2157 | ac->ac_inode, | ||
| 2158 | bg, | ||
| 2159 | bg_bh, | ||
| 2160 | res->sr_bit_offset, | ||
| 2161 | res->sr_bits); | ||
| 2162 | if (ret < 0) { | ||
| 2163 | mlog_errno(ret); | ||
| 2164 | goto out; | ||
| 2165 | } | ||
| 2166 | |||
| 2167 | mlog(0, "Allocated %u bits from suballocator %llu\n", res->sr_bits, | ||
| 2168 | (unsigned long long)di_blkno); | ||
| 2169 | |||
| 2170 | atomic_inc(&OCFS2_SB(ac->ac_inode->i_sb)->alloc_stats.bg_allocs); | ||
| 2171 | |||
| 2172 | BUG_ON(res->sr_bits != 1); | ||
| 2173 | |||
| 2174 | *suballoc_loc = res->sr_bg_blkno; | ||
| 2175 | *suballoc_bit = res->sr_bit_offset; | ||
| 2176 | ac->ac_bits_given++; | ||
| 2177 | ocfs2_save_inode_ac_group(dir, ac); | ||
| 2178 | |||
| 2179 | out: | ||
| 2180 | brelse(bg_bh); | ||
| 2181 | |||
| 2182 | return ret; | ||
| 2183 | } | ||
| 2184 | |||
| 2019 | int ocfs2_claim_new_inode(handle_t *handle, | 2185 | int ocfs2_claim_new_inode(handle_t *handle, |
| 2020 | struct inode *dir, | 2186 | struct inode *dir, |
| 2021 | struct buffer_head *parent_fe_bh, | 2187 | struct buffer_head *parent_fe_bh, |
| @@ -2567,7 +2733,8 @@ out: | |||
| 2567 | * suballoc_bit. | 2733 | * suballoc_bit. |
| 2568 | */ | 2734 | */ |
| 2569 | static int ocfs2_get_suballoc_slot_bit(struct ocfs2_super *osb, u64 blkno, | 2735 | static int ocfs2_get_suballoc_slot_bit(struct ocfs2_super *osb, u64 blkno, |
| 2570 | u16 *suballoc_slot, u16 *suballoc_bit) | 2736 | u16 *suballoc_slot, u64 *group_blkno, |
| 2737 | u16 *suballoc_bit) | ||
| 2571 | { | 2738 | { |
| 2572 | int status; | 2739 | int status; |
| 2573 | struct buffer_head *inode_bh = NULL; | 2740 | struct buffer_head *inode_bh = NULL; |
| @@ -2604,6 +2771,8 @@ static int ocfs2_get_suballoc_slot_bit(struct ocfs2_super *osb, u64 blkno, | |||
| 2604 | *suballoc_slot = le16_to_cpu(inode_fe->i_suballoc_slot); | 2771 | *suballoc_slot = le16_to_cpu(inode_fe->i_suballoc_slot); |
| 2605 | if (suballoc_bit) | 2772 | if (suballoc_bit) |
| 2606 | *suballoc_bit = le16_to_cpu(inode_fe->i_suballoc_bit); | 2773 | *suballoc_bit = le16_to_cpu(inode_fe->i_suballoc_bit); |
| 2774 | if (group_blkno) | ||
| 2775 | *group_blkno = le64_to_cpu(inode_fe->i_suballoc_loc); | ||
| 2607 | 2776 | ||
| 2608 | bail: | 2777 | bail: |
| 2609 | brelse(inode_bh); | 2778 | brelse(inode_bh); |
| @@ -2621,7 +2790,8 @@ bail: | |||
| 2621 | */ | 2790 | */ |
| 2622 | static int ocfs2_test_suballoc_bit(struct ocfs2_super *osb, | 2791 | static int ocfs2_test_suballoc_bit(struct ocfs2_super *osb, |
| 2623 | struct inode *suballoc, | 2792 | struct inode *suballoc, |
| 2624 | struct buffer_head *alloc_bh, u64 blkno, | 2793 | struct buffer_head *alloc_bh, |
| 2794 | u64 group_blkno, u64 blkno, | ||
| 2625 | u16 bit, int *res) | 2795 | u16 bit, int *res) |
| 2626 | { | 2796 | { |
| 2627 | struct ocfs2_dinode *alloc_di; | 2797 | struct ocfs2_dinode *alloc_di; |
| @@ -2642,10 +2812,8 @@ static int ocfs2_test_suballoc_bit(struct ocfs2_super *osb, | |||
| 2642 | goto bail; | 2812 | goto bail; |
| 2643 | } | 2813 | } |
| 2644 | 2814 | ||
| 2645 | if (alloc_di->i_suballoc_loc) | 2815 | bg_blkno = group_blkno ? group_blkno : |
| 2646 | bg_blkno = le64_to_cpu(alloc_di->i_suballoc_loc); | 2816 | ocfs2_which_suballoc_group(blkno, bit); |
| 2647 | else | ||
| 2648 | bg_blkno = ocfs2_which_suballoc_group(blkno, bit); | ||
| 2649 | status = ocfs2_read_group_descriptor(suballoc, alloc_di, bg_blkno, | 2817 | status = ocfs2_read_group_descriptor(suballoc, alloc_di, bg_blkno, |
| 2650 | &group_bh); | 2818 | &group_bh); |
| 2651 | if (status < 0) { | 2819 | if (status < 0) { |
| @@ -2680,6 +2848,7 @@ bail: | |||
| 2680 | int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res) | 2848 | int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res) |
| 2681 | { | 2849 | { |
| 2682 | int status; | 2850 | int status; |
| 2851 | u64 group_blkno = 0; | ||
| 2683 | u16 suballoc_bit = 0, suballoc_slot = 0; | 2852 | u16 suballoc_bit = 0, suballoc_slot = 0; |
| 2684 | struct inode *inode_alloc_inode; | 2853 | struct inode *inode_alloc_inode; |
| 2685 | struct buffer_head *alloc_bh = NULL; | 2854 | struct buffer_head *alloc_bh = NULL; |
| @@ -2687,7 +2856,7 @@ int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res) | |||
| 2687 | mlog_entry("blkno: %llu", (unsigned long long)blkno); | 2856 | mlog_entry("blkno: %llu", (unsigned long long)blkno); |
| 2688 | 2857 | ||
| 2689 | status = ocfs2_get_suballoc_slot_bit(osb, blkno, &suballoc_slot, | 2858 | status = ocfs2_get_suballoc_slot_bit(osb, blkno, &suballoc_slot, |
| 2690 | &suballoc_bit); | 2859 | &group_blkno, &suballoc_bit); |
| 2691 | if (status < 0) { | 2860 | if (status < 0) { |
| 2692 | mlog(ML_ERROR, "get alloc slot and bit failed %d\n", status); | 2861 | mlog(ML_ERROR, "get alloc slot and bit failed %d\n", status); |
| 2693 | goto bail; | 2862 | goto bail; |
| @@ -2715,7 +2884,7 @@ int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res) | |||
| 2715 | } | 2884 | } |
| 2716 | 2885 | ||
| 2717 | status = ocfs2_test_suballoc_bit(osb, inode_alloc_inode, alloc_bh, | 2886 | status = ocfs2_test_suballoc_bit(osb, inode_alloc_inode, alloc_bh, |
| 2718 | blkno, suballoc_bit, res); | 2887 | group_blkno, blkno, suballoc_bit, res); |
| 2719 | if (status < 0) | 2888 | if (status < 0) |
| 2720 | mlog(ML_ERROR, "test suballoc bit failed %d\n", status); | 2889 | mlog(ML_ERROR, "test suballoc bit failed %d\n", status); |
| 2721 | 2890 | ||
diff --git a/fs/ocfs2/suballoc.h b/fs/ocfs2/suballoc.h index a017dd3ee7d9..b8afabfeede4 100644 --- a/fs/ocfs2/suballoc.h +++ b/fs/ocfs2/suballoc.h | |||
| @@ -56,6 +56,9 @@ struct ocfs2_alloc_context { | |||
| 56 | u64 ac_max_block; /* Highest block number to allocate. 0 is | 56 | u64 ac_max_block; /* Highest block number to allocate. 0 is |
| 57 | is the same as ~0 - unlimited */ | 57 | is the same as ~0 - unlimited */ |
| 58 | 58 | ||
| 59 | int ac_find_loc_only; /* hack for reflink operation ordering */ | ||
| 60 | struct ocfs2_suballoc_result *ac_find_loc_priv; /* */ | ||
| 61 | |||
| 59 | struct ocfs2_alloc_reservation *ac_resv; | 62 | struct ocfs2_alloc_reservation *ac_resv; |
| 60 | }; | 63 | }; |
| 61 | 64 | ||
| @@ -197,4 +200,22 @@ int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_extent_tree *et, | |||
| 197 | struct ocfs2_alloc_context **meta_ac); | 200 | struct ocfs2_alloc_context **meta_ac); |
| 198 | 201 | ||
| 199 | int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res); | 202 | int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res); |
| 203 | |||
| 204 | |||
| 205 | |||
| 206 | /* | ||
| 207 | * The following two interfaces are for ocfs2_create_inode_in_orphan(). | ||
| 208 | */ | ||
| 209 | int ocfs2_find_new_inode_loc(struct inode *dir, | ||
| 210 | struct buffer_head *parent_fe_bh, | ||
| 211 | struct ocfs2_alloc_context *ac, | ||
| 212 | u64 *fe_blkno); | ||
| 213 | |||
| 214 | int ocfs2_claim_new_inode_at_loc(handle_t *handle, | ||
| 215 | struct inode *dir, | ||
| 216 | struct ocfs2_alloc_context *ac, | ||
| 217 | u64 *suballoc_loc, | ||
| 218 | u16 *suballoc_bit, | ||
| 219 | u64 di_blkno); | ||
| 220 | |||
| 200 | #endif /* _CHAINALLOC_H_ */ | 221 | #endif /* _CHAINALLOC_H_ */ |
diff --git a/fs/proc/page.c b/fs/proc/page.c index 180cf5a0bd67..3b8b45660331 100644 --- a/fs/proc/page.c +++ b/fs/proc/page.c | |||
| @@ -146,7 +146,7 @@ u64 stable_page_flags(struct page *page) | |||
| 146 | u |= kpf_copy_bit(k, KPF_HWPOISON, PG_hwpoison); | 146 | u |= kpf_copy_bit(k, KPF_HWPOISON, PG_hwpoison); |
| 147 | #endif | 147 | #endif |
| 148 | 148 | ||
| 149 | #ifdef CONFIG_IA64_UNCACHED_ALLOCATOR | 149 | #ifdef CONFIG_ARCH_USES_PG_UNCACHED |
| 150 | u |= kpf_copy_bit(k, KPF_UNCACHED, PG_uncached); | 150 | u |= kpf_copy_bit(k, KPF_UNCACHED, PG_uncached); |
| 151 | #endif | 151 | #endif |
| 152 | 152 | ||
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 439fc1f1c1c4..271afc48b9a5 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
| @@ -224,7 +224,8 @@ static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) | |||
| 224 | /* We don't show the stack guard page in /proc/maps */ | 224 | /* We don't show the stack guard page in /proc/maps */ |
| 225 | start = vma->vm_start; | 225 | start = vma->vm_start; |
| 226 | if (vma->vm_flags & VM_GROWSDOWN) | 226 | if (vma->vm_flags & VM_GROWSDOWN) |
| 227 | start += PAGE_SIZE; | 227 | if (!vma_stack_continue(vma->vm_prev, vma->vm_start)) |
| 228 | start += PAGE_SIZE; | ||
| 228 | 229 | ||
| 229 | seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n", | 230 | seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n", |
| 230 | start, | 231 | start, |
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 1b27b5688f62..da3fefe91a8f 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
| @@ -340,7 +340,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
| 340 | char *p; | 340 | char *p; |
| 341 | 341 | ||
| 342 | p = d_path(&file->f_path, last_sysfs_file, sizeof(last_sysfs_file)); | 342 | p = d_path(&file->f_path, last_sysfs_file, sizeof(last_sysfs_file)); |
| 343 | if (p) | 343 | if (!IS_ERR(p)) |
| 344 | memmove(last_sysfs_file, p, strlen(p) + 1); | 344 | memmove(last_sysfs_file, p, strlen(p) + 1); |
| 345 | 345 | ||
| 346 | /* need attr_sd for attr and ops, its parent for kobj */ | 346 | /* need attr_sd for attr and ops, its parent for kobj */ |
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index ea79072f5210..286e36e21dae 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c | |||
| @@ -440,12 +440,7 @@ _xfs_buf_find( | |||
| 440 | ASSERT(btp == bp->b_target); | 440 | ASSERT(btp == bp->b_target); |
| 441 | if (bp->b_file_offset == range_base && | 441 | if (bp->b_file_offset == range_base && |
| 442 | bp->b_buffer_length == range_length) { | 442 | bp->b_buffer_length == range_length) { |
| 443 | /* | ||
| 444 | * If we look at something, bring it to the | ||
| 445 | * front of the list for next time. | ||
| 446 | */ | ||
| 447 | atomic_inc(&bp->b_hold); | 443 | atomic_inc(&bp->b_hold); |
| 448 | list_move(&bp->b_hash_list, &hash->bh_list); | ||
| 449 | goto found; | 444 | goto found; |
| 450 | } | 445 | } |
| 451 | } | 446 | } |
| @@ -1443,8 +1438,7 @@ xfs_alloc_bufhash( | |||
| 1443 | { | 1438 | { |
| 1444 | unsigned int i; | 1439 | unsigned int i; |
| 1445 | 1440 | ||
| 1446 | btp->bt_hashshift = external ? 3 : 8; /* 8 or 256 buckets */ | 1441 | btp->bt_hashshift = external ? 3 : 12; /* 8 or 4096 buckets */ |
| 1447 | btp->bt_hashmask = (1 << btp->bt_hashshift) - 1; | ||
| 1448 | btp->bt_hash = kmem_zalloc_large((1 << btp->bt_hashshift) * | 1442 | btp->bt_hash = kmem_zalloc_large((1 << btp->bt_hashshift) * |
| 1449 | sizeof(xfs_bufhash_t)); | 1443 | sizeof(xfs_bufhash_t)); |
| 1450 | for (i = 0; i < (1 << btp->bt_hashshift); i++) { | 1444 | for (i = 0; i < (1 << btp->bt_hashshift); i++) { |
| @@ -1938,7 +1932,8 @@ xfs_buf_init(void) | |||
| 1938 | if (!xfs_buf_zone) | 1932 | if (!xfs_buf_zone) |
| 1939 | goto out; | 1933 | goto out; |
| 1940 | 1934 | ||
| 1941 | xfslogd_workqueue = create_workqueue("xfslogd"); | 1935 | xfslogd_workqueue = alloc_workqueue("xfslogd", |
| 1936 | WQ_RESCUER | WQ_HIGHPRI, 1); | ||
| 1942 | if (!xfslogd_workqueue) | 1937 | if (!xfslogd_workqueue) |
| 1943 | goto out_free_buf_zone; | 1938 | goto out_free_buf_zone; |
| 1944 | 1939 | ||
diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h index d072e5ff923b..2a05614f0b92 100644 --- a/fs/xfs/linux-2.6/xfs_buf.h +++ b/fs/xfs/linux-2.6/xfs_buf.h | |||
| @@ -137,7 +137,6 @@ typedef struct xfs_buftarg { | |||
| 137 | size_t bt_smask; | 137 | size_t bt_smask; |
| 138 | 138 | ||
| 139 | /* per device buffer hash table */ | 139 | /* per device buffer hash table */ |
| 140 | uint bt_hashmask; | ||
| 141 | uint bt_hashshift; | 140 | uint bt_hashshift; |
| 142 | xfs_bufhash_t *bt_hash; | 141 | xfs_bufhash_t *bt_hash; |
| 143 | 142 | ||
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index 237f5ffb2ee8..3b9e626f7cd1 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c | |||
| @@ -785,6 +785,8 @@ xfs_ioc_fsgetxattr( | |||
| 785 | { | 785 | { |
| 786 | struct fsxattr fa; | 786 | struct fsxattr fa; |
| 787 | 787 | ||
| 788 | memset(&fa, 0, sizeof(struct fsxattr)); | ||
| 789 | |||
| 788 | xfs_ilock(ip, XFS_ILOCK_SHARED); | 790 | xfs_ilock(ip, XFS_ILOCK_SHARED); |
| 789 | fa.fsx_xflags = xfs_ip2xflags(ip); | 791 | fa.fsx_xflags = xfs_ip2xflags(ip); |
| 790 | fa.fsx_extsize = ip->i_d.di_extsize << ip->i_mount->m_sb.sb_blocklog; | 792 | fa.fsx_extsize = ip->i_d.di_extsize << ip->i_mount->m_sb.sb_blocklog; |
| @@ -907,6 +909,13 @@ xfs_ioctl_setattr( | |||
| 907 | return XFS_ERROR(EIO); | 909 | return XFS_ERROR(EIO); |
| 908 | 910 | ||
| 909 | /* | 911 | /* |
| 912 | * Disallow 32bit project ids because on-disk structure | ||
| 913 | * is 16bit only. | ||
| 914 | */ | ||
| 915 | if ((mask & FSX_PROJID) && (fa->fsx_projid > (__uint16_t)-1)) | ||
| 916 | return XFS_ERROR(EINVAL); | ||
| 917 | |||
| 918 | /* | ||
| 910 | * If disk quotas is on, we make sure that the dquots do exist on disk, | 919 | * If disk quotas is on, we make sure that the dquots do exist on disk, |
| 911 | * before we start any other transactions. Trying to do this later | 920 | * before we start any other transactions. Trying to do this later |
| 912 | * is messy. We don't care to take a readlock to look at the ids | 921 | * is messy. We don't care to take a readlock to look at the ids |
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 68be25dcd301..b1fc2a6bfe83 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c | |||
| @@ -664,7 +664,7 @@ xfs_vn_fiemap( | |||
| 664 | fieinfo->fi_extents_max + 1; | 664 | fieinfo->fi_extents_max + 1; |
| 665 | bm.bmv_count = min_t(__s32, bm.bmv_count, | 665 | bm.bmv_count = min_t(__s32, bm.bmv_count, |
| 666 | (PAGE_SIZE * 16 / sizeof(struct getbmapx))); | 666 | (PAGE_SIZE * 16 / sizeof(struct getbmapx))); |
| 667 | bm.bmv_iflags = BMV_IF_PREALLOC; | 667 | bm.bmv_iflags = BMV_IF_PREALLOC | BMV_IF_NO_HOLES; |
| 668 | if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) | 668 | if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) |
| 669 | bm.bmv_iflags |= BMV_IF_ATTRFORK; | 669 | bm.bmv_iflags |= BMV_IF_ATTRFORK; |
| 670 | if (!(fieinfo->fi_flags & FIEMAP_FLAG_SYNC)) | 670 | if (!(fieinfo->fi_flags & FIEMAP_FLAG_SYNC)) |
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 23f14e595c18..f90dadd5a968 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
| @@ -5533,12 +5533,24 @@ xfs_getbmap( | |||
| 5533 | map[i].br_startblock)) | 5533 | map[i].br_startblock)) |
| 5534 | goto out_free_map; | 5534 | goto out_free_map; |
| 5535 | 5535 | ||
| 5536 | nexleft--; | ||
| 5537 | bmv->bmv_offset = | 5536 | bmv->bmv_offset = |
| 5538 | out[cur_ext].bmv_offset + | 5537 | out[cur_ext].bmv_offset + |
| 5539 | out[cur_ext].bmv_length; | 5538 | out[cur_ext].bmv_length; |
| 5540 | bmv->bmv_length = | 5539 | bmv->bmv_length = |
| 5541 | max_t(__int64_t, 0, bmvend - bmv->bmv_offset); | 5540 | max_t(__int64_t, 0, bmvend - bmv->bmv_offset); |
| 5541 | |||
| 5542 | /* | ||
| 5543 | * In case we don't want to return the hole, | ||
| 5544 | * don't increase cur_ext so that we can reuse | ||
| 5545 | * it in the next loop. | ||
| 5546 | */ | ||
| 5547 | if ((iflags & BMV_IF_NO_HOLES) && | ||
| 5548 | map[i].br_startblock == HOLESTARTBLOCK) { | ||
| 5549 | memset(&out[cur_ext], 0, sizeof(out[cur_ext])); | ||
| 5550 | continue; | ||
| 5551 | } | ||
| 5552 | |||
| 5553 | nexleft--; | ||
| 5542 | bmv->bmv_entries++; | 5554 | bmv->bmv_entries++; |
| 5543 | cur_ext++; | 5555 | cur_ext++; |
| 5544 | } | 5556 | } |
diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h index 7cf7220e7d5f..87c2e9d02288 100644 --- a/fs/xfs/xfs_fs.h +++ b/fs/xfs/xfs_fs.h | |||
| @@ -114,8 +114,10 @@ struct getbmapx { | |||
| 114 | #define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */ | 114 | #define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */ |
| 115 | #define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */ | 115 | #define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */ |
| 116 | #define BMV_IF_DELALLOC 0x8 /* rtn status BMV_OF_DELALLOC if req */ | 116 | #define BMV_IF_DELALLOC 0x8 /* rtn status BMV_OF_DELALLOC if req */ |
| 117 | #define BMV_IF_NO_HOLES 0x10 /* Do not return holes */ | ||
| 117 | #define BMV_IF_VALID \ | 118 | #define BMV_IF_VALID \ |
| 118 | (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC|BMV_IF_DELALLOC) | 119 | (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC| \ |
| 120 | BMV_IF_DELALLOC|BMV_IF_NO_HOLES) | ||
| 119 | 121 | ||
| 120 | /* bmv_oflags values - returned for each non-header segment */ | 122 | /* bmv_oflags values - returned for each non-header segment */ |
| 121 | #define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */ | 123 | #define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */ |
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 66d585c6917c..4c7c7bfb2b2f 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
| @@ -2299,15 +2299,22 @@ xfs_alloc_file_space( | |||
| 2299 | e = allocatesize_fsb; | 2299 | e = allocatesize_fsb; |
| 2300 | } | 2300 | } |
| 2301 | 2301 | ||
| 2302 | /* | ||
| 2303 | * The transaction reservation is limited to a 32-bit block | ||
| 2304 | * count, hence we need to limit the number of blocks we are | ||
| 2305 | * trying to reserve to avoid an overflow. We can't allocate | ||
| 2306 | * more than @nimaps extents, and an extent is limited on disk | ||
| 2307 | * to MAXEXTLEN (21 bits), so use that to enforce the limit. | ||
| 2308 | */ | ||
| 2309 | resblks = min_t(xfs_fileoff_t, (e - s), (MAXEXTLEN * nimaps)); | ||
| 2302 | if (unlikely(rt)) { | 2310 | if (unlikely(rt)) { |
| 2303 | resrtextents = qblocks = (uint)(e - s); | 2311 | resrtextents = qblocks = resblks; |
| 2304 | resrtextents /= mp->m_sb.sb_rextsize; | 2312 | resrtextents /= mp->m_sb.sb_rextsize; |
| 2305 | resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0); | 2313 | resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0); |
| 2306 | quota_flag = XFS_QMOPT_RES_RTBLKS; | 2314 | quota_flag = XFS_QMOPT_RES_RTBLKS; |
| 2307 | } else { | 2315 | } else { |
| 2308 | resrtextents = 0; | 2316 | resrtextents = 0; |
| 2309 | resblks = qblocks = \ | 2317 | resblks = qblocks = XFS_DIOSTRAT_SPACE_RES(mp, resblks); |
| 2310 | XFS_DIOSTRAT_SPACE_RES(mp, (uint)(e - s)); | ||
| 2311 | quota_flag = XFS_QMOPT_RES_REGBLKS; | 2318 | quota_flag = XFS_QMOPT_RES_REGBLKS; |
| 2312 | } | 2319 | } |
| 2313 | 2320 | ||
