Nghiên cứu tìm hiểu về quản lý Bộ nhớ trong HĐH Linux

35 745 2
Nghiên cứu tìm hiểu về quản lý  Bộ nhớ trong HĐH Linux

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

 BỘ CÔNG THƯƠNG TRƯỜNG ĐẠI HỌC CÔNG NGHIỆP HÀ NỘI KHOA CNTT - - BÀI TẬP LỚN Đề tài : Nghiên cứu tìm hiểu quản Bộ nhớ HĐH Linux MÔN: NGUYÊN HỆ ĐIỀU HÀNH Giáo viên hướng dẫn: Th.s Nguyễn Tuấn Tú Nhóm số Lớp: ĐH Khoa học Máy tính 3- K9 Hà Nội, 2016  BỘ CÔNG THƯƠNG TRƯỜNG ĐẠI HỌC CÔNG NGHIỆP HÀ NỘI KHOA CNTT - - BÀI TẬP LỚN Đề tài : Nghiên cứu tìm hiểu quản Bộ nhớ HĐH Linux MÔN: NGUYÊN HỆ ĐIỀU HÀNH Giáo viên hướng dẫn: Th.s Nguyễn Tuấn Tú Nhóm số Lớp: ĐH Khoa học Máy tính 3- K9 Nhóm sinh viên thực hiện: Bùi Quốc Đại Nguyễn Huy Đại Trần Văn Huy Võ Văn Trí Vũ Hữu Trí - Mã SV : 0941060190 - Mã SV : 0941060189 - Mã SV : 0941060246 - Mã SV : 0941060227 - Mã SV : 0941060191 Hà Nội, 2016 MỤC LỤC Lời mở đầu Chương : MỞ ĐẦU 1.1.Giới thiệu hệ điều hành Linux 1.2.Tổng quan quản nhớ Linux Chương : CƠ CHẾ PHÂN ĐOẠN, PHÂN TRANG 2.1.Sự phân đoạn 2.2.Sự phân trang 2.2.1 Nhu cầu phân trang 2.2.2 Trang lưu trữ ( page cache) .5 2.2.3.Bảng trang 2.2.4 Định vị giải phóng trang Chương : QUẢN BỘ NHỚ ẢO, KHÔNG GIAN HOÁN ĐỔI 3.1.Khái niệm nhớ ảo, không gian hoán đổi 13 3.2 Mô hình nhớ ảo .13 3.3.Tạo không gian hoán đổi .16 3.4 Sử dụng không gian hoán đổi 18 3.5 Định vị không gian hoán đổi .20 Chương : CƠ CHẾ QUẢN BỘ NHỚ VẬT LÝ, ÁNH XẠ BỘ NHỚ 4.1.Quản nhớ vật 21 4.1.1.Bộ định vùng 21 4.1.2.Các vùng 22 4.2.Ánh xạ nhớ .22 Chương : CẤP PHÁT VÀ GIẢI PHÓNG VÙNG NHỚ 5.1.Cấp phát vùng nhớ 24 5.1.1 Cấp phát vùng nhớ giản đơn 24 5.1.2 Cấp phát vùng nhớ lớn 25 5.1.3 Vùng nhớ bảo vệ .28 5.1.4 Một số hàm cấp phát vùng nhớ khác .29 5.2.Giải phóng vùng nhớ 30 5.3.Truy xuất trỏ NULL 31 Lời nói đầu Trong hệ thống kiến thức chuyên ngành trang bị cho sinh viên khoa Công nghệ Thông tin, môn Nguyên hệ điều hành cung cấp nội dung kiến thức chung hệ điều hành máy tính Nó giúp người học nắm bắt nguyên nguyên tắc làm việc hệ điều hành máy tính tổng quát Từ áp dụng để làm việc tốt với hệ điều hành cụ thể thực tế, hình dung xu hướng phát triển hệ điều hành tương lai Chúng ta hiểu máy tính muốn hoạt động cần phải cài lên hệ điều hành Hiện có nhiều hệ điều hành để sử dụng Nhưng phổ biến ba hệ điều hành : Window, Mac OS Linux Khác với Window Mac OS, Linux hệ điều hành mã nguồn mở với nhiều phiên xây dựng Vài năm qua, Linux thực tạo cách mạng lĩnh vực máy tính Sự phát triển chúng mang lại cho máy tính thật đáng kinh ngạc: hệ điều hành đa nhiệm, đa người dùng Với mã nguồn mở, sử dụng Linux an toàn ứng dụng Windows Linux đem đến cho lợi ích kinh tế với nhiều phần mềm miễn phí Mã nguồn mở hệ điều hành chương trình Linux tài liệu vô giá để học hỏi tham khảo Một hệ điều hành muốn chạy ổn định phải có chế quảnnhớ hiệu Và đề tài mà nhóm em nghiên cứu, tìm hiểu đề tài : Nghiên cứu tìm hiêủ quảnnhớ HĐH Linux Do thời gian, trình độ có hạn, thông tin, tài liệu sưu tầm từ nhiều nguồn khác Nên đề tài nhóm em tránh khỏi có nhiều sai sót, hạn chế Mong thầy bạn thông cảm, góp ý, sửa chữa để đề tài nhóm em hoàn thiện Chúng em xin chân thành cảm ơn Ths Nguyễn Tuấn Tú hướng dẫn giúp đỡ chúng em trình bày hoàn thành đề tài Nhóm sinh viên thực CHƯƠNG MỞ ĐẦU 1.1.Giới thiệu hệ điều hành Linux Linux hệ điều hành họ UNIX miễn phí sử dụng rộng rãi Được viết vào năm 1991 Linus Toward, hệ điều hành Linux thu thành công định Là hệ điều hành đa nhiệm, đa người dùng, Linux chạy nhiều phần cứng khác Với tính ổn định mềm dẻo, Linux dần sử dụng nhiều máy chủ máy trạm mạng máy tính Linux cho phép dễ dàng thực việc tích hợp hệ điều hành khác mạng máy tính Windows, Novell, Apple Ngoài ra, với tính mã nguồn mở, hệ điều hành cho phép khả tùy biến cao, thích hợp cho nhu cầu sử dụng cụ thể Hình 1.1: Biểu tượng Hệ điều hành Linux 1.2.Tổng quan quản nhớ Linux Trong hệ thống máy tính, nhớ tài nguyên khan Cho dù có nhớ không đáp ứng đủ nhu cầu người sử dụng Các máy tính cá nhân trang bị 128Mb nhớ Các máy chủ server lên đến hàng gigabyte nhớ Thế nhu cầu nhớ không thỏa mãn Linux có cách tiếp cận quản nhớ rõ ràng Các ứng dụng Linux không phép truy cập trực tiếp vào địa vật nhớ Linux cung cấp cho chương trình chạy HĐH - gọi tiến trình - mô hình đánh địa phẳng không phân đoạn segment:offset DOS Mỗi tiến trình thấy vùng không gian địa riêng Hầu tất phiên UNIX cung cấp cách bảo vệ nhớ theo chế bảo đảm tiến trình ghi đè lên vùng nhớ tiến trình khác hoạt động vùng nhớ hệ thống Nói chung, nhớ mà hệ thống cấp phát cho tiến trình đọc ghi tiến trình khác Trong hầu hết hệ thống Linux UNIX, trỏ sử dụng số nguyên 32 bit trỏ đến ô nhớ cụ thể Với 32 bit, hệ thống đánh địa lên đến GB nhớ Mô hình nhớ phẳng dễ truy xuất xử nhớ phân đoạn segment:offset Ngoài ra, vài hệ thống sử dụng mô hình địa 64 bit, không gian địa mở rộng đến terabyte Để tăng dung lượng nhớ sẵn có, Linux cài đặt chương trình phân trang đĩa tức lượng không gian hoán đổi phân bố đĩa Khi hệ thống yêu cầu nhiều nhớ vật lý, đưa trang không hoạt động đĩa, nhờ bạn chạy ứng dụng lớn lúc hỗ trợ nhiều người sử dụng Tuy vậy, việc hoán đổi không thay RAM vật lý, chậm cần nhiều thời gian để truy cập đĩa Kernel cài đặt khối nhớ hợp cho chương trình người sử dụng đệm đĩa tạm thời (disk cache) Theo cách này, tất nhớ trống dành để nhớ tạm nhớ đệm (cache) giảm xuống xử chạy chương trình lớn CHƯƠNG2 CƠ CHẾ PHÂN ĐOẠN, PHÂN TRANG 2.1.Sự phân đoạn Linux sử dụng chế phân đoạn để phân tách vùng nhớ cấp phát cho hạt nhân tiến trình Hai phân đoạn liên quan đến 3GB ( từ đến 0xBFFF FFFF ) không gian địa tiến trình nội dung chúng đọc chỉnh sửa chế độ người dùng chế độ Kernel Hai phân đoạn liên quan đến GB thứ (từ 0xC000 0000 đến 0xFFFF FFFF ) không gian địa tiến trình nội dung đọc chỉnh sửa chế độ Kernel Theo cách này, liệu mã Kernel bảo vệ khỏi truy cập không hợp tiến trình chế độ người dùng Hình 2.1: Cơ chế phân đoạn tách vùng nhớ cấp phát cho hạt nhân tiến trình 2.2.Sự phân trang 2.2.1 Nhu cầu phân trang Vì có nhớ vật so với nhớ ảo nên HĐH phải trọng để không lãng phí nhớ vật Một cách để tiết kiệm nhớ vật load trang ảo mà sử dụng chương trình thực thi Ví dụ, chương trình sở liệu thực truy vấn vào sở liệu Trong trường hợp toàn sở liệu load vào nhớ mà load ghi có liên quan Việc mà load trang ảo vào nhớ chúng truy cập dẫn đến nhu cầu phân trang 2.2.2 Trang lưu trữ ( page cache) Cache tầng nằm phần quản nhớ kernel phần vào đĩa Các trang mà kernel hoán đổi không ghi trực tiếp lên đĩa mà ghi vào cache Khi cần vùng nhớ trống kernel ghi trang từ cache đĩa Đặc tính chung trang danh sách trang theo chuẩn LRU(Least Recently Used : sử dụng thường xuyên nhất) : - active_list : trang có page -> age > 0, chứa không chứa liệu, ánh xạ mục bảng trang tiến trình - inactive_dirty_list : trang có page -> age == 0, chứa không chứa liệu, không ánh xạ mục bảng trang tiến trình - inactive_clean_list : vùng có inactive_dirty_list riêng nó, chứa trang clean với age == 0, không ánh xạ mục bảng trang tiến trình Trong quản lỗi trang, kernel tìm kiếm trang lỗi page cache Nếu lỗi tìm thấy đưa đến active_list để đưa thông báo * Vòng đời User Page Trang P đọc từ đĩa vào nhớ lưu vào page cache Có thể xảy trường hợp sau : * Tiến trình A muốn truy cập vào trang P Nó trình quản lỗi trang kiểm tra xem có tương ứng với file ánh xạ không Sau lưu vào page cache bảng trang tiến trình Từ vòng đời trang bắt đầu active_list, nơi mà lưu giữ kể sử dụng : * Trang P đọc suốt trình hoạt động đầu đọc hoán đổi, lưu vào page cache Trong trường hợp này, mà trang đọc đơn giản phần cluster khối đĩa Một loạt trang liên tiếp đĩa đọc mà không cần biết trang có cần hay không Chúng ta không cần quan tâm đến việc thông báo cho trang chúng không dùng, chúng phục hồi cho dù không tham chiếu đến \ : * Trang P đọc suốt trình hoạt động đầu đọc cluster ánh xạ nhớ Trong trường hợp này, chuỗi trang liền tiếp sau trang lỗi file ánh xạ nhớ đọc Những trang bắt đầu vòng đời chúng page cache kết hợp với file ánh xạ nhớ active_list Trang P ghi tiến trình, có chứa liệu ( dirty ) Lúc trang P active_list Trang P không sử dụng thời gian Sự kích hoạt định kì hàm kswapd() (kernel swap daemon) giảm dần biến đếm page->age Hàm kswapd() hoạt động nhiều nhu cầu nhớ tăng Thời gian tồn trang P giảm dần xuống (age == 0) không tham chiếu, dẫn đến kích hoạt hàm re_fill inactive() Nếu nhớ đầy, hàm swap_out gọi hàm kswapd() để cố gắng lấy lại trang từ không gian địa ảo tiến trình A Vì trang P không Cách tốt để tạo file swap mà vùng trống thực đoạn lệnh sau: $ dd if=/dev/zero of=/extra-swap bs=1024 Count=1024 1024+0 records in 1024+0 records out $ Trong đó, /extra-swap tên file swap kích thước cho sau count= Kích thước tốt bội số kernel ghi trang nhớ, trang có kích thước Kbyte Nếu kích thước bội số cặp Kbyte cuối không sử dụng Một phân vùng swap đặc biệt Bạn tạo giống phân vùng khác, khác sử dụng phân vùng thô, không chứa file hệ thống Phân vùng swap đánh dấu loại 82 ( Linux swap ), điều giúp cho việc liệt kê phân vùng rõ ràng không hoàn toàn cần thiết kernel Sau bạn tạo phân vùng swap phân vùng swap, bạn cần ghi chữ ký lên nơi bắt đầu Chữ ký sử dụng kernel chứa số thông tin việc quản Đoạn lệnh để làm việc hàm mkswap(), sử dụng sau : $ mkswap /extra-swap 1024 Setting up swapspace, size = 1044480 bytes $ Chú ý không gian hoán đổi chưa sử dụng, tồn kernel không sử dụng để cung cấp nhớ ảo Bạn nên cẩn thận sử dụng hàm 17 mkswap() không kiểm tra file hay phân vùng sử dụng chưa Bạn dễ dàng ghi đè lên file hay phân vùng quan trọng với hàm mkswap() Tốt hết bạn nên sử dụng hàm cài đặt lên hệ thống bạn Trình quản nhớ Linux giới hạn kích thước không gian hoán đổi 127MB Tuy nhiên bạn sử dụng lúc tới không gian hoán đổi nên tổng kích thước lên đến 1GB Điều không đúng, với phiên kernel giới hạn thay đổi tùy thuộc vào cấu trúc Ví dụ xử i386 giới hạn 2GB 3.4.Sử dụng không gian hoán đổi Một không gian hoán đổi khởi tạo lấy để sử dụng nhờ lệnh swapon Lệnh báo cho kernel không gian hoán đổi sử dụng Đường dẫn đến không gian hoán đổi cấp đối số, để bắt đầu hoán đổi file swap tạm thời, bạn sử dụng đoạn lệnh sau : $ swapon /extra-swap $ Không gian hoán đổi sử dụng tự động cách liệt kê chúng file /etc/fstab /dev/hda8 none swap sw 0 /swapfile none swap sw 0 Đoạn mã khởi động chạy lệnh swapon -a, lệnh bắt đầu thực hoán đổi tất không gian hoán đổi liệt kê file /etc/fstab Do lệnh swapon thường sử dụng cần hoán đổi thêm Bạn quản việc sử dụng không gian hoán đổi với lệnh free Nó cho biết tổng số không gian hoán đổi sử dụng $ free 18 total used free shared buffers Mem: 15152 -/+ buffers: Swap: 14896 12368 32452 6684 256 12404 2528 2784 25768 $ Một không gian hoán đổi bị loại bỏ lệnh swapoff Thông thường không cần phải dùng lệnh ngoại trừ không gian hoán đổi tạm thời Bất kì trang sử dụng không gian hoán đổi đưa vào trước Nếu đủ nhớ vật để chứa chúng chúng đưa đến không gian hoán đổi khác Nếu đủ nhớ ảo để chứa tất trang, Linux bắt đầu dừng lại (thrash), sau khoảng thời gian dài khôi phục lúc hệ thống sử dụng Bạn nên kiểm tra ( lệnh free ) để xem có đủ nhớ trống không trước loại bỏ không gian hoán đổi Tất không gian hoán đổi sử dụng tự động nhờ lệnh swapon -a loại bỏ với lệnh swapoff -a, lệnh tìm thông tin file /etc/fstab để loại bỏ Còn không gian hoán đổi điều khiển tay sử dụng bình thường Đôi có nhiều không gian hoán đổi sử dụng có nhiều nhớ vật trống Điều xảy thời điểm có nhu cầu hoán đổi, sau tiến trình lớn chiếm nhiều nhớ vật kết thúc giải phóng nhớ Dữ liệu đưa không tự động đưa vào cần, nhớ vật trống thời gian dài Bạn không cần phải lo lắng điều mà cần biết điều xảy 19 3.5.Định vị không gian hoán đổi Người ta thường nói bạn nên định vị không gian hoán đổi gấp đôi nhớ vật lý, quy luật Bạn xem cách làm sau : + Dự đoán tổng nhớ mà bạn cần Đây số lượng nhớ lớn mà bạn cần thời điểm đó, tổng nhớ cần thiết cho tất chương trình mà bạn muốn chạy lúc Lệnh free ps có ích để đoán lượng nhớ cần dùng + Cộng thêm vào dự đoán bước 1, dự đoán kích thước chương trình sai bạn quên số chương trình mà bạn muốn chạy, để chắn bạn nên chuẩn bị không gian phụ để dùng cần Nên định vị dư thiếu không dư nhiều gây lãng phí Bạn nên làm tròn lên thành số chẵn megabyte + Dựa tính toán trên, bạn biết cần tổng cộng nhớ Vì vậy, để định vị không gian hoán đổi, bạn cần lấy tổng nhớ dùng trừ cho nhớ vật + Nếu không gian hoán đổi mà bạn tính lớn hai lần nhớ vật bạn nên mua thêm RAM, không hiệu máy thấp Tốt hết nên có vài không gian hoán đổi cho dù theo tính toán bạn không cần Linux sử dụng không gian hoán đổi linh hoạt Linux đưa trang nhớ không sử dụng cho dù nhớ chưa cần dùng Điều giúp tránh việc chờ đợi hoán đổi cần nhớ 20 CHƯƠNG4 CƠ CHẾ QUẢN BỘ NHỚ VẬT LÝ, ÁNH XẠ BỘ NHỚ 4.1 Quản nhớ vật 4.1.1 Bộ định vùng Các bảng trang kernel ánh xạ tối đa nhớ vật vào dãy địa bắt đầu PAGE_OFFSET Các trang vật chiếm đoạn mã liệu kernel dành riêng không sử dụng cho mục đích khác Các trang vật khác định vị cho nhớ ảo tiến trình, nhớ đệm, nhớ ảo kernel, cần Để làm điều này, phải có cách theo dõi trang vật sử dụng sử dụng Bộ định vùng ( zone allocator ) quản nhớ vật Bất kì mã kernel gọi tới định vùng thông qua hàm alloc_pages() cấp khối gồm 2n trang canh đường biên tương ứng Chúng ta chuyển khối trang lại cho định vùng nhờ hàm free_pages() Số mũ n gọi thứ tự định vùng Các khối không cần phải giải phóng giống cách mà chúng xác định, phải giải phóng xác, khung trang khối phải có số tham chiếu khác Ví dụ, bạn yêu cầu khối trang, sau giải phóng khối trang khối trang đó, muốn làm điều trước hết bạn phải tăng biến tham chiếu trang khối trang bạn định vị khối trang, có biến tham chiếu trang khối tăng, mặt khác đoạn mã giải phóng trang không giải phóng trang có biến tham chiếu 0, nên biến tham chiếu trang khác phải điều khiển tay Việc tăng tất biến tham chiếu trang khối không cần thiết đồng thời làm tăng kích thước đoạn mã định vị trang 21 4.1.2 Các vùng Các dãy trang vật khác có thuộc tính khác nhau, phục vụ cho mục đích kernel Ví dụ, DMA ( Direct Memory Access ) cho phép thiết bị ngoại vi đọc viết liệu trực tiếp lên RAM mà can thiệp CPU, làm việc với địa vật nhỏ 16MB Một vài hệ thống có nhớ vật nhiều ánh xạ PAGE_OFFSET 4GB, trang vật truy cập trực tiếp đến kernel, chúng phải quản theo cách khác Bộ định vùng quản khác cách chia nhớ thành vùng xem vùng đơn vị cho định vị Cấu trúc liệu root quản định vùng zone_struct, gồm tập hợp tất liệu liên quan đến việc quản vùng cụ thể Zonelist_struct bao gồm mảng trỏ zone_struct gfp_mask chế định vị sử dụng zone_list Zone_struct offset địa offset nơi bắt đầu vùng nhớ vật 4.2 Ánh xạ nhớ (mm3 - Memory Mapping) Khi ảnh thực hiện, nội dung phải đưa vào không gian địa ảo tiến trình File thực thi không thực mang vào nhớ vật lý, mà thay vào đơn liên kết đến nhớ ảo tiến trình Sau ảnh mang vào nhớ phần chương trình tham chiếu ứng dụng chạy Sự liên kết ảnh vào không gian địa ảo tiến trình gọi ánh xạ nhớ Mỗi nhớ ảo tiến trình miêu tả cấu trúc liệu mm_struct Cấu trúc chứa thông tin ảnh thực thi trỏ đến số cấu trúc liệu vm_area_struct Mỗi cấu trúc liệu vm_area_struct mô tả điểm bắt đầu kết thúc khu vực nhớ ảo, quyền truy cập tiến trình đến nhớ hoạt động nhớ Các hoạt động tập hợp thường trình (routine) 22 mà Linux phải sử dụng xử khu vực nhớ ảo Ví dụ, hoạt động nhớ ảo thực hiệu chỉnh tiến trình tìm cách truy cập vào nhớ ảo mà giá trị tương ứng nhớ vật ( thông qua lỗi trang ) Hoạt động hoạt động nopage Hoạt động nopage sử dụng Linux yêu cầu trang ảnh thực thi nhớ Khi ảnh thực thi ánh xạ vào địa ảo tiến trình, tập hợp cấu trúc liệu vm_area_struct thực Mỗi cấu trúc liệu vm_area_struct mô tả phần ảnh thực thi, đoạn mã thực thi, liệu khởi tạo ( biến ), liệu không khởi tạo, Linux hỗ trợ số hoạt động nhớ ảo chuẩn Hình 4.1: Các khu vực nhớ ảo 23 CHƯƠNG CẤP PHÁT VÀ GIẢI PHÓNG VÙNG NHỚ 5.1 Cấp phát vùng nhớ 5.1.1 Cấp phát vùng nhớ giản đơn Vùng nhớ giản đơn vùng nhớ có kích thước nhỏ kích thước nhớ vật Chúng ta cấp phát vùng nhớ cho tiến trinh dựa vào hàm malloc( ) thư viện C chuẩn void *malloc(size_t size); Không giống DOS Windows, sử dụng hàm này, không cần phải khai báo thư viện malloc.h size : kích thước vùng nhớ muốn cấp phát, size có kiểu size_t Thực size_t định nghĩa kiểu nguyên không dấu unsigned int Ví dụ : memoryl.c #include #include #include #define Kich_thuoc(1024*1024) //1 Mb nhớ /*………………………………………………………*/ int main(){ char *some_memory; int megabyte=Kich_thuoc; int exit_code=EXIT_FAILURE; some_memory=(char*) malloc(megabyte); if(some_memory != NULL){ sprintf(some_memory,"Cap phat vung nho gian don "); printf(" % s", some_memory); exit_code=EXIT_SUCCESS; } exit(exit_code) 24 } Chương trinh yêu cầu hàm malloc() cấp phát trả trỏ trỏ đến vùng nhớ MB Chương trình kiểm tra trỏ Null để đảm bảo hàm malloc() cấp phát thành công Tiếp theo chuỗi "Cap phat vung nho gian don" đặt vào phần đầu vùng nhớ Tuy chuỗi " Cap phat vung nho gian don" không chiếm hết MB vùng nhớ hàm malloc() cấp phát vùng nhớ kích cỡ chương trình yêu cầu.Hàm malloc( ) trả trỏ *void( trỏ dạng tổng quát), chương trình cần phải chuyển trỏ dạng char* để truy cập đến vùng nhớ theo dạng chuỗi kí tự Hàm malloc() bảo đảm vùng nhớ cấp phát dãy byte xếp liền Vì này, định nghĩa kiểu trả trỏ liệu 5.1.2 Cấp phát vùng nhớ lớn Vùng nhớ lớn có kích thước vượt kích thước thật nhớ vật Do chưa biết hệ thống có chấp nhận hay không nên trình xin cấp phát, hệ thống ngắt ngang nhớ cạn kiệt Ví dụ : memory2.c #include #include #include #define Kich_thuoc(1024*1024) //1 Mb nhớ /*………………………………………………*/ int main( ){ char *some_memory; size_t size_to_allocate= Kich_thuoc; int megs_obtained=0; while( megs_obtainde

Ngày đăng: 16/04/2017, 12:20

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan