| @@ -255,6 +255,152 @@ static inline struct hugepage_subpool *subpool_vma(struct vm_area_struct *vma) · 254 unmodified lines |
| 255 | 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 | 404 | /* Helper that removes a struct file_region from the resv_map cache and returns |
| 259 | 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 | 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 | 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 | 7020 | * Search for a shareable pmd page for hugetlb. In any case calls pmd_alloc() |
| 7017 | 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 | 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 | 7107 | pte_t *huge_pmd_share(struct mm_struct *mm, struct vm_area_struct *vma, |
| 7145 | 7108 | unsigned long addr, pud_t *pud) |
| 7146 | 7109 | { |