| @@ -255,6 +255,152 @@ static inline struct hugepage_subpool *subpool_vma(struct vm_area_struct *vma) · 254 unmodified lines |
| 255 | return subpool_inode(file_inode(vma->vm_file)); | 255 | return subpool_inode(file_inode(vma->vm_file)); |
| 256 | } | 256 | } |
| 257 | | 257 | |
| | 258 | /* |
| | 259 | * hugetlb vma_lock helper routines |
| | 260 | */ |
| | 261 | static bool __vma_shareable_lock(struct vm_area_struct *vma) |
| | 262 | { |
| | 263 | return vma->vm_flags & (VM_MAYSHARE | VM_SHARED) && |
| | 264 | vma->vm_private_data; |
| | 265 | } |
| | 266 | |
| | 267 | void hugetlb_vma_lock_read(struct vm_area_struct *vma) |
| | 268 | { |
| | 269 | if (__vma_shareable_lock(vma)) { |
| | 270 | struct hugetlb_vma_lock *vma_lock = vma->vm_private_data; |
| | 271 | |
| | 272 | down_read(&vma_lock->rw_sema); |
| | 273 | } |
| | 274 | } |
| | 275 | |
| | 276 | void hugetlb_vma_unlock_read(struct vm_area_struct *vma) |
| | 277 | { |
| | 278 | if (__vma_shareable_lock(vma)) { |
| | 279 | struct hugetlb_vma_lock *vma_lock = vma->vm_private_data; |
| | 280 | |
| | 281 | up_read(&vma_lock->rw_sema); |
| | 282 | } |
| | 283 | } |
| | 284 | |
| | 285 | void hugetlb_vma_lock_write(struct vm_area_struct *vma) |
| | 286 | { |
| | 287 | if (__vma_shareable_lock(vma)) { |
| | 288 | struct hugetlb_vma_lock *vma_lock = vma->vm_private_data; |
| | 289 | |
| | 290 | down_write(&vma_lock->rw_sema); |
| | 291 | } |
| | 292 | } |
| | 293 | |
| | 294 | void hugetlb_vma_unlock_write(struct vm_area_struct *vma) |
| | 295 | { |
| | 296 | if (__vma_shareable_lock(vma)) { |
| | 297 | struct hugetlb_vma_lock *vma_lock = vma->vm_private_data; |
| | 298 | |
| | 299 | up_write(&vma_lock->rw_sema); |
| | 300 | } |
| | 301 | } |
| | 302 | |
| | 303 | int hugetlb_vma_trylock_write(struct vm_area_struct *vma) |
| | 304 | { |
| | 305 | struct hugetlb_vma_lock *vma_lock = vma->vm_private_data; |
| | 306 | |
| | 307 | if (!__vma_shareable_lock(vma)) |
| | 308 | return 1; |
| | 309 | |
| | 310 | return down_write_trylock(&vma_lock->rw_sema); |
| | 311 | } |
| | 312 | |
| | 313 | void hugetlb_vma_assert_locked(struct vm_area_struct *vma) |
| | 314 | { |
| | 315 | if (__vma_shareable_lock(vma)) { |
| | 316 | struct hugetlb_vma_lock *vma_lock = vma->vm_private_data; |
| | 317 | |
| | 318 | lockdep_assert_held(&vma_lock->rw_sema); |
| | 319 | } |
| | 320 | } |
| | 321 | |
| | 322 | void hugetlb_vma_lock_release(struct kref *kref) |
| | 323 | { |
| | 324 | struct hugetlb_vma_lock *vma_lock = container_of(kref, |
| | 325 | struct hugetlb_vma_lock, refs); |
| | 326 | |
| | 327 | kfree(vma_lock); |
| | 328 | } |
| | 329 | |
| | 330 | static void __hugetlb_vma_unlock_write_put(struct hugetlb_vma_lock *vma_lock) |
| | 331 | { |
| | 332 | struct vm_area_struct *vma = vma_lock->vma; |
| | 333 | |
| | 334 | /* |
| | 335 | * vma_lock structure may or not be released as a result of put, |
| | 336 | * it certainly will no longer be attached to vma so clear pointer. |
| | 337 | * Semaphore synchronizes access to vma_lock->vma field. |
| | 338 | */ |
| | 339 | vma_lock->vma = NULL; |
| | 340 | vma->vm_private_data = NULL; |
| | 341 | up_write(&vma_lock->rw_sema); |
| | 342 | kref_put(&vma_lock->refs, hugetlb_vma_lock_release); |
| | 343 | } |
| | 344 | |
| | 345 | static void __hugetlb_vma_unlock_write_free(struct vm_area_struct *vma) |
| | 346 | { |
| | 347 | if (__vma_shareable_lock(vma)) { |
| | 348 | struct hugetlb_vma_lock *vma_lock = vma->vm_private_data; |
| | 349 | |
| | 350 | __hugetlb_vma_unlock_write_put(vma_lock); |
| | 351 | } |
| | 352 | } |
| | 353 | |
| | 354 | static void hugetlb_vma_lock_free(struct vm_area_struct *vma) |
| | 355 | { |
| | 356 | /* |
| | 357 | * Only present in sharable vmas. |
| | 358 | */ |
| | 359 | if (!vma || !__vma_shareable_lock(vma)) |
| | 360 | return; |
| | 361 | |
| | 362 | if (vma->vm_private_data) { |
| | 363 | struct hugetlb_vma_lock *vma_lock = vma->vm_private_data; |
| | 364 | |
| | 365 | down_write(&vma_lock->rw_sema); |
| | 366 | __hugetlb_vma_unlock_write_put(vma_lock); |
| | 367 | } |
| | 368 | } |
| | 369 | |
| | 370 | static void hugetlb_vma_lock_alloc(struct vm_area_struct *vma) |
| | 371 | { |
| | 372 | struct hugetlb_vma_lock *vma_lock; |
| | 373 | |
| | 374 | /* Only establish in (flags) sharable vmas */ |
| | 375 | if (!vma || !(vma->vm_flags & VM_MAYSHARE)) |
| | 376 | return; |
| | 377 | |
| | 378 | /* Should never get here with non-NULL vm_private_data */ |
| | 379 | if (vma->vm_private_data) |
| | 380 | return; |
| | 381 | |
| | 382 | vma_lock = kmalloc(sizeof(*vma_lock), GFP_KERNEL); |
| | 383 | if (!vma_lock) { |
| | 384 | /* |
| | 385 | * If we can not allocate structure, then vma can not |
| | 386 | * participate in pmd sharing. This is only a possible |
| | 387 | * performance enhancement and memory saving issue. |
| | 388 | * However, the lock is also used to synchronize page |
| | 389 | * faults with truncation. If the lock is not present, |
| | 390 | * unlikely races could leave pages in a file past i_size |
| | 391 | * until the file is removed. Warn in the unlikely case of |
| | 392 | * allocation failure. |
| | 393 | */ |
| | 394 | pr_warn_once("HugeTLB: unable to allocate vma specific lock\n"); |
| | 395 | return; |
| | 396 | } |
| | 397 | |
| | 398 | kref_init(&vma_lock->refs); |
| | 399 | init_rwsem(&vma_lock->rw_sema); |
| | 400 | vma_lock->vma = vma; |
| | 401 | vma->vm_private_data = vma_lock; |
| | 402 | } |
| | 403 | |
| 258 | /* Helper that removes a struct file_region from the resv_map cache and returns | 404 | /* Helper that removes a struct file_region from the resv_map cache and returns |
| 259 | * it for use. | 405 | * it for use. |
| 260 | */ | 406 | */ |
| @@ -6613,7 +6759,8 @@ bool hugetlb_reserve_pages(struct inode *inode, · 6352 unmodified lines |
| 6613 | } | 6759 | } |
| 6614 | | 6760 | |
| 6615 | /* | 6761 | /* |
| 6616 | * vma specific semaphore used for pmd sharing synchronization | 6762 | * vma specific semaphore used for pmd sharing and fault/truncation |
| | 6763 | * synchronization |
| 6617 | */ | 6764 | */ |
| 6618 | hugetlb_vma_lock_alloc(vma); | 6765 | hugetlb_vma_lock_alloc(vma); |
| 6619 | | 6766 | |
| @@ -6869,149 +7016,6 @@ void adjust_range_if_pmd_sharing_possible(struct vm_area_struct *vma, · 249 unmodified lines |
| 6869 | *end = ALIGN(*end, PUD_SIZE); | 7016 | *end = ALIGN(*end, PUD_SIZE); |
| 6870 | } | 7017 | } |
| 6871 | | 7018 | |
| 6872 | static bool __vma_shareable_flags_pmd(struct vm_area_struct *vma) | | |
| 6873 | { | | |
| 6874 | return vma->vm_flags & (VM_MAYSHARE | VM_SHARED) && | | |
| 6875 | vma->vm_private_data; | | |
| 6876 | } | | |
| 6877 | | | |
| 6878 | void hugetlb_vma_lock_read(struct vm_area_struct *vma) | | |
| 6879 | { | | |
| 6880 | if (__vma_shareable_flags_pmd(vma)) { | | |
| 6881 | struct hugetlb_vma_lock *vma_lock = vma->vm_private_data; | | |
| 6882 | | | |
| 6883 | down_read(&vma_lock->rw_sema); | | |
| 6884 | } | | |
| 6885 | } | | |
| 6886 | | | |
| 6887 | void hugetlb_vma_unlock_read(struct vm_area_struct *vma) | | |
| 6888 | { | | |
| 6889 | if (__vma_shareable_flags_pmd(vma)) { | | |
| 6890 | struct hugetlb_vma_lock *vma_lock = vma->vm_private_data; | | |
| 6891 | | | |
| 6892 | up_read(&vma_lock->rw_sema); | | |
| 6893 | } | | |
| 6894 | } | | |
| 6895 | | | |
| 6896 | void hugetlb_vma_lock_write(struct vm_area_struct *vma) | | |
| 6897 | { | | |
| 6898 | if (__vma_shareable_flags_pmd(vma)) { | | |
| 6899 | struct hugetlb_vma_lock *vma_lock = vma->vm_private_data; | | |
| 6900 | | | |
| 6901 | down_write(&vma_lock->rw_sema); | | |
| 6902 | } | | |
| 6903 | } | | |
| 6904 | | | |
| 6905 | void hugetlb_vma_unlock_write(struct vm_area_struct *vma) | | |
| 6906 | { | | |
| 6907 | if (__vma_shareable_flags_pmd(vma)) { | | |
| 6908 | struct hugetlb_vma_lock *vma_lock = vma->vm_private_data; | | |
| 6909 | | | |
| 6910 | up_write(&vma_lock->rw_sema); | | |
| 6911 | } | | |
| 6912 | } | | |
| 6913 | | | |
| 6914 | int hugetlb_vma_trylock_write(struct vm_area_struct *vma) | | |
| 6915 | { | | |
| 6916 | struct hugetlb_vma_lock *vma_lock = vma->vm_private_data; | | |
| 6917 | | | |
| 6918 | if (!__vma_shareable_flags_pmd(vma)) | | |
| 6919 | return 1; | | |
| 6920 | | | |
| 6921 | return down_write_trylock(&vma_lock->rw_sema); | | |
| 6922 | } | | |
| 6923 | | | |
| 6924 | void hugetlb_vma_assert_locked(struct vm_area_struct *vma) | | |
| 6925 | { | | |
| 6926 | if (__vma_shareable_flags_pmd(vma)) { | | |
| 6927 | struct hugetlb_vma_lock *vma_lock = vma->vm_private_data; | | |
| 6928 | | | |
| 6929 | lockdep_assert_held(&vma_lock->rw_sema); | | |
| 6930 | } | | |
| 6931 | } | | |
| 6932 | | | |
| 6933 | void hugetlb_vma_lock_release(struct kref *kref) | | |
| 6934 | { | | |
| 6935 | struct hugetlb_vma_lock *vma_lock = container_of(kref, | | |
| 6936 | struct hugetlb_vma_lock, refs); | | |
| 6937 | | | |
| 6938 | kfree(vma_lock); | | |
| 6939 | } | | |
| 6940 | | | |
| 6941 | static void __hugetlb_vma_unlock_write_put(struct hugetlb_vma_lock *vma_lock) | | |
| 6942 | { | | |
| 6943 | struct vm_area_struct *vma = vma_lock->vma; | | |
| 6944 | | | |
| 6945 | /* | | |
| 6946 | * vma_lock structure may or not be released as a result of put, | | |
| 6947 | * it certainly will no longer be attached to vma so clear pointer. | | |
| 6948 | * Semaphore synchronizes access to vma_lock->vma field. | | |
| 6949 | */ | | |
| 6950 | vma_lock->vma = NULL; | | |
| 6951 | vma->vm_private_data = NULL; | | |
| 6952 | up_write(&vma_lock->rw_sema); | | |
| 6953 | kref_put(&vma_lock->refs, hugetlb_vma_lock_release); | | |
| 6954 | } | | |
| 6955 | | | |
| 6956 | static void __hugetlb_vma_unlock_write_free(struct vm_area_struct *vma) | | |
| 6957 | { | | |
| 6958 | if (__vma_shareable_flags_pmd(vma)) { | | |
| 6959 | struct hugetlb_vma_lock *vma_lock = vma->vm_private_data; | | |
| 6960 | | | |
| 6961 | __hugetlb_vma_unlock_write_put(vma_lock); | | |
| 6962 | } | | |
| 6963 | } | | |
| 6964 | | | |
| 6965 | static void hugetlb_vma_lock_free(struct vm_area_struct *vma) | | |
| 6966 | { | | |
| 6967 | /* | | |
| 6968 | * Only present in sharable vmas. | | |
| 6969 | */ | | |
| 6970 | if (!vma || !__vma_shareable_flags_pmd(vma)) | | |
| 6971 | return; | | |
| 6972 | | | |
| 6973 | if (vma->vm_private_data) { | | |
| 6974 | struct hugetlb_vma_lock *vma_lock = vma->vm_private_data; | | |
| 6975 | | | |
| 6976 | down_write(&vma_lock->rw_sema); | | |
| 6977 | __hugetlb_vma_unlock_write_put(vma_lock); | | |
| 6978 | } | | |
| 6979 | } | | |
| 6980 | | | |
| 6981 | static void hugetlb_vma_lock_alloc(struct vm_area_struct *vma) | | |
| 6982 | { | | |
| 6983 | struct hugetlb_vma_lock *vma_lock; | | |
| 6984 | | | |
| 6985 | /* Only establish in (flags) sharable vmas */ | | |
| 6986 | if (!vma || !(vma->vm_flags & VM_MAYSHARE)) | | |
| 6987 | return; | | |
| 6988 | | | |
| 6989 | /* Should never get here with non-NULL vm_private_data */ | | |
| 6990 | if (vma->vm_private_data) | | |
| 6991 | return; | | |
| 6992 | | | |
| 6993 | vma_lock = kmalloc(sizeof(*vma_lock), GFP_KERNEL); | | |
| 6994 | if (!vma_lock) { | | |
| 6995 | /* | | |
| 6996 | * If we can not allocate structure, then vma can not | | |
| 6997 | * participate in pmd sharing. This is only a possible | | |
| 6998 | * performance enhancement and memory saving issue. | | |
| 6999 | * However, the lock is also used to synchronize page | | |
| 7000 | * faults with truncation. If the lock is not present, | | |
| 7001 | * unlikely races could leave pages in a file past i_size | | |
| 7002 | * until the file is removed. Warn in the unlikely case of | | |
| 7003 | * allocation failure. | | |
| 7004 | */ | | |
| 7005 | pr_warn_once("HugeTLB: unable to allocate vma specific lock\n"); | | |
| 7006 | return; | | |
| 7007 | } | | |
| 7008 | | | |
| 7009 | kref_init(&vma_lock->refs); | | |
| 7010 | init_rwsem(&vma_lock->rw_sema); | | |
| 7011 | vma_lock->vma = vma; | | |
| 7012 | vma->vm_private_data = vma_lock; | | |
| 7013 | } | | |
| 7014 | | | |
| 7015 | /* | 7019 | /* |
| 7016 | * Search for a shareable pmd page for hugetlb. In any case calls pmd_alloc() | 7020 | * Search for a shareable pmd page for hugetlb. In any case calls pmd_alloc() |
| 7017 | * and returns the corresponding pte. While this is not necessary for the | 7021 | * and returns the corresponding pte. While this is not necessary for the |
| @@ -7100,47 +7104,6 @@ int huge_pmd_unshare(struct mm_struct *mm, struct vm_area_struct *vma, · 82 unmodified lines |
| 7100 | | 7104 | |
| 7101 | #else /* !CONFIG_ARCH_WANT_HUGE_PMD_SHARE */ | 7105 | #else /* !CONFIG_ARCH_WANT_HUGE_PMD_SHARE */ |
| 7102 | | 7106 | |
| 7103 | void hugetlb_vma_lock_read(struct vm_area_struct *vma) | | |
| 7104 | { | | |
| 7105 | } | | |
| 7106 | | | |
| 7107 | void hugetlb_vma_unlock_read(struct vm_area_struct *vma) | | |
| 7108 | { | | |
| 7109 | } | | |
| 7110 | | | |
| 7111 | void hugetlb_vma_lock_write(struct vm_area_struct *vma) | | |
| 7112 | { | | |
| 7113 | } | | |
| 7114 | | | |
| 7115 | void hugetlb_vma_unlock_write(struct vm_area_struct *vma) | | |
| 7116 | { | | |
| 7117 | } | | |
| 7118 | | | |
| 7119 | int hugetlb_vma_trylock_write(struct vm_area_struct *vma) | | |
| 7120 | { | | |
| 7121 | return 1; | | |
| 7122 | } | | |
| 7123 | | | |
| 7124 | void hugetlb_vma_assert_locked(struct vm_area_struct *vma) | | |
| 7125 | { | | |
| 7126 | } | | |
| 7127 | | | |
| 7128 | void hugetlb_vma_lock_release(struct kref *kref) | | |
| 7129 | { | | |
| 7130 | } | | |
| 7131 | | | |
| 7132 | static void __hugetlb_vma_unlock_write_free(struct vm_area_struct *vma) | | |
| 7133 | { | | |
| 7134 | } | | |
| 7135 | | | |
| 7136 | static void hugetlb_vma_lock_free(struct vm_area_struct *vma) | | |
| 7137 | { | | |
| 7138 | } | | |
| 7139 | | | |
| 7140 | static void hugetlb_vma_lock_alloc(struct vm_area_struct *vma) | | |
| 7141 | { | | |
| 7142 | } | | |
| 7143 | | | |
| 7144 | pte_t *huge_pmd_share(struct mm_struct *mm, struct vm_area_struct *vma, | 7107 | pte_t *huge_pmd_share(struct mm_struct *mm, struct vm_area_struct *vma, |
| 7145 | unsigned long addr, pud_t *pud) | 7108 | unsigned long addr, pud_t *pud) |
| 7146 | { | 7109 | { |