首页
关于
Search
1
2023 年保研经验贴
123 阅读
2
Linux Kernel-THP阅读分析[Hang up]
41 阅读
3
CSAPP 1. 计算机系统漫游
40 阅读
4
Rust入门笔记 2.函数、所有权与复合类型
40 阅读
5
Rust入门笔记 3.切片、向量与字符串
38 阅读
内核
源码分析
Rust
语法
读书笔记
深入理解计算机系统
技术之外
登录
Search
yyi
累计撰写
19
篇文章
累计收到
0
条评论
首页
栏目
内核
源码分析
Rust
语法
读书笔记
深入理解计算机系统
技术之外
页面
关于
搜索到
19
篇与
的结果
2023-09-13
2023 年保研经验贴
1 个人情况院校:末九专业:理科试验班,计算机方向成绩:11/24,综合排名预计 2-5/24英语:CET-6 472,CET-4 517竞赛:全国信安一等,逆向工程方向奖学金:约等于无科研:一点没有项目:Mips 流水线处理器课设,字节跳动夏令营 Go 语言字节码设计与解释器实现。实习:一段字节后端开发,业务开发,CRUD。一段腾讯后端开发,基础架构,连 CRUD 都没有了,K8s 运维。目标:清北华五网安/软工/SYS,除了 AI 都行。如果去不上考虑雅思润了。最终去向:北京大学计算机学院计算机系统结构直博(还没 928,希望不是半场开香槟)。2 夏令营申请学校/学院类型入营优营复旦大学/计算机学院不考虑直博是未参加清华大学/深圳研究生院专硕是否北京大学/计算机学院直博是是上海交通大学/网络安全学院不考虑直博否否南京大学/计算机学院学硕否否南京大学/软件学院专硕提前拒绝否中国科学院/计算技术研究所学硕提前拒绝否注:复旦夏令营撞期末,提前跟捞我的老师说希望不要浪费他名额,但是有点晚了联系清华本部的老师,说在深圳借个名额,深圳老师又给个考核,没做但是被捞进去了南软出名单前一天晚上老师打电话,问捞了是不是确定会去,答复撞了 ICT 的营,祝老师招生顺利ICT 面试完老师承诺一定能入营,但是北大优营之后提前和老师说接 offer 不去了3 夏令营参营清华大学深圳国际研究生院夏令营流程网络机试,和本部一起,不过是双机位在线第一天活动、破冰,请假了第二天面试,分综合面试和学术面试第三天公布优营,请假了机试机试三道题,一道送分题,爆搜即可,一道大模拟,硬钢了 4h 发现是合并数据,最后爆 0,第三题据说是贪心就能拿很多分,笑死,根本没看面试面试发挥的垃圾的一批,面试老师给我的感觉也一般,可能就是不 match 吧综合面试:一个论文摘要,读一句翻译一句,虽然翻译的一般但是应该还行,大体看懂了一些英文问题对答,包括喜欢什么书为什么之类的,很基础的问题还有一些中文问题对答,不是很值得记录技术面试:5 分钟自我介绍,期间被老师打断说你不要讲了,继续下一步吧(在我没超时的前提下)。这也是我对面试印象很差的原因。后面问的问题都很没营养,包括排名差为什么能保研,你们班的制度什么样子,你的竞赛含金量是怎么样的,怎么证明。还问了机试做的一般,有什么想法么。一些流程之外本来我是做网安的,联系的本部网研院某老师,某老师在本部夏令营已结束的时候让我加他微信(此时距离我发邮件已过去 20 天),和我说可以同时报本部和清深的夏令营,他会从清深 X 老师处借一个名额。此时我其实不太想报的,因为已经有意向去 PKU 了,想着假装忙忘了就好了,但是截止前一天被老师催了,只好报了。X 老师是研控上一大篇 1.0,第一印象其实一般。此外,在我期末的时候 X 老师安排了考核,我说我可能要复习,没时间做。但是最后还是做了下。X 老师后来让我联系他的一个研究生,借研究生之口劝我报一个澳洲什么学校(完 全 没 听 过)的直博联培,并称极端情况下如果夏令营发的 offer 的同学都不去联培,预推免有愿意去的,可能会鸽夏令营的 offer。至此,我对这个组印象更差了。此外我也很迷惑,不是说好的本部老师从你这借名额么,你咋还要把我推出去呢?所以其实我对 THUSZ 这个营也没怎么上心...,当然,看上去 X 老师对我也没怎么上心。北京大学计算机学院夏令营流程北大的夏令营看上去是三天,实际上只有两天。第一天活动+答疑+机试,第二天或第三天各研究所自行安排,我的面试在第二天上午。机试机试1小时40分钟,签了协议,而且也是去向,这里就不多说了4 联系老师4.1 清华大学网研,网安,副教授1老师对我做的物联网安全相关的内容比较感兴趣,但是这块我做的不多,而且觉得希望不大,遂拒绝面试网研,网安,副教授2非常奇葩。同学推荐我的老师,发了邮件之后20天回的我,当时感觉就是是不是被别人鸽了。我没有报清网的夏令营,老师说可以在清深借老师3的名额招我,遂让我联系老师3.其实我已经有点婉拒了,因为当时觉得北大稳了(事实证明并不稳,一样过了考核的一位同学面试被挂了)。深圳,网安,副教授3。。。。。。这..清深著名坑导。都在上面了。4.2 北京大学计算机,系统,教授1联系后给了面试,第一次主要提了三点直博能接受么?做sys能受得了么校区在昌平能接受么?都能,做个项目吧。遂留了个Linux内存模块,让读了然后整理上下层接口,给出迁移到FreeBSD的方案。二面晚了40分钟,明说只给我15分钟,之后还有别的同学,然而我准备了一个小时,只好强行随机应变。4.3 中科院计算所处理器,安全,研究员1 :李炼老师老师人很好,先找了两个导师面我,我自己觉得答得不是很好,但是已经到我自己水平线了。没想到过了。我因为个人原因,还放了老师面试鸽子。后来面试聊了一个小时,说对我很感兴趣,可以夏令营再来聊聊。聊的问题主要涉及到逆向工具的使用、对工具的理解,基础的OS知识,对Fuzz的了解,对漏洞的了解之类的。4.4 复旦大学计算机,安全,副教授1和副教授2差不多,而且答应捞营,但是捞营后面考核还要靠自己。确实把我捞进去了。可惜入营名单公布前两天,学院公布考试时间,撞了。这时候找老师让他别推荐了,结果有点晚,还是入营了。计算机,软件,教授1给我实验室信息,让我看看,我对副教授2比较感兴趣,就说我自行联系他了计算机,软件,副教授2两个老师一起考核了我一下,还是一些在逆向工程中做了的一些事,以及一些基础知识,包括对逆向工具的理解(递归下降、线性扫描),如何归类竞赛题目、遇到什么题目会有什么方法(我归类主要是混淆和加密,混淆包括编译器类型的混淆、虚拟机、基于系统特性的混淆,主要就是动静结合,简单说了下断点和原理什么的)。面完说捞不了营,但是进营一定要我。4.5 武汉大学计算机,软件,教授1WHU老师非常热情,而且简单聊几次之后感觉老师人也很好。面了一个小时,和前面的都差不多。提了个小问题:如果有一万个相似的二进制让我分析怎么办。后面聊了聊他对组里的管理,包括做的各种方向。短短接触觉得这个老师至少人很好,如果没有更好的offer其实挺想去的。他甚至打电话督促我让我报夏令营,可惜当时北大已经面完了。4.6 南京大学软件,软件,副教授1只有邮件往来,主要聊了下是否能接受专硕,看上去就是到他那给企业做横向,其实我觉得挺能接受的。后来出入营前一天晚上十点多给我打电话,问捞了我应该能进,捞了的话是不是一定会去。因为和计算所冲突了,遂拒。
2023年09月13日
123 阅读
0 评论
7 点赞
2023-09-09
Linux Kernel-Zpool 接口阅读
Linux Kernel-Zpool 接口阅读最近还是在做zswap的迁移,需要整理一下zpool的接口功能,以决定是迁移过去一个现成的还是自己实现一个简单的。1 Zpool作用Zpool只是一个接口层,由zbud、zsmalloc等进行具体实现。Zpool提供了一个内存池,用以存放被压缩的内存。因为它是一个接口,其实我们只需要简单的关注注册数据结构,就能了解到它的一些关键作用。2 Driver Structstruct zpool_driver { char *type; struct module *owner; atomic_t refcount; struct list_head list; void *(*create)(const char *name, gfp_t gfp, const struct zpool_ops *ops, struct zpool *zpool); void (*destroy)(void *pool); bool malloc_support_movable; int (*malloc)(void *pool, size_t size, gfp_t gfp, unsigned long *handle); void (*free)(void *pool, unsigned long handle); int (*shrink)(void *pool, unsigned int pages, unsigned int *reclaimed); bool sleep_mapped; void *(*map)(void *pool, unsigned long handle, enum zpool_mapmode mm); void (*unmap)(void *pool, unsigned long handle); u64 (*total_size)(void *pool); };refcount、list的作用都是字面意思。Type是当前driver的名字,索引driver的时候会用到。下面的函数是zpool后端提供给接口的实现,我们会在下一节里介绍其作用。3 暴露接口3.1 zpool_register_drivervoid zpool_register_driver(struct zpool_driver *driver); int zpool_unregister_driver(struct zpool_driver *driver)该函数暴露给所有zpool的实现,由他们在启动时注册。该函数初始化了引用计数、将被注册的driver加入到zpool的链表中。与其相对应的是zpool_unregister_driver,注销driver该接口评估为不需要迁移。3.2 zpool_get_driverstatic struct zpool_driver *zpool_get_driver(const char *type) static void zpool_put_driver(struct zpool_driver *driver)给定一个zpool驱动名字,返回对应的zpool_driver。并且增加对应driver的引用计数。与其相对应的是zpool_put_driver该接口评估为不需要迁移。3.3 zpool_has_pool、zpool_create_pool、zpool_destry_poolbool zpool_has_pool(char *type) struct zpool *zpool_create_pool(const char *type, const char *name, gfp_t gfp, const struct zpool_ops *ops) void zpool_destroy_pool(struct zpool *zpool)分别承担检测给定的driver是否可用、创建一个指定类型的zpool和销毁一个已经存在的zpool。该接口评估为不需要迁移3.4 zpool_malloc_support_movablebool zpool_malloc_support_movable(struct zpool *zpool)返回driver是否支持迁移的字段,评估为不需要迁移。3.5 driver实现函数3.5.1 zpool_malloc、zpool_free、zpool_shrinkint zpool_malloc(struct zpool *zpool, size_t size, gfp_t gfp, unsigned long *handle) void zpool_free(struct zpool *zpool, unsigned long handle) int zpool_shrink(struct zpool *zpool, unsigned int pages, unsigned int *reclaimed)在给定的zpool中申请大小为size的空间,并把申请得到的句柄放在handle中在给定的zpool中释放给定的handle的空间。zpool_shrink可能未被实现,如果实现,尝试驱逐当前正在使用的句柄。3.5.2 zpool_map_handle、zpool_unmap_handlevoid *zpool_map_handle(struct zpool *zpool, unsigned long handle, enum zpool_mapmode mapmode) void zpool_unmap_handle(struct zpool *zpool, unsigned long handle)根据给定的pool和handle,映射到连续的地址上取消映射,解锁相关的锁3.5.3 zpool_get_total_sizeu64 zpool_get_total_size(struct zpool *zpool)获取zpool所占用的内存空间
2023年09月09日
16 阅读
0 评论
0 点赞
2023-09-07
Typora+PicGo+兰空图床环境搭建
1. Why最开始上传图片,都是图片存本地,然后一个个传到Typecho上改。非常的麻烦不优雅,影响更博心情。于是就想找个方便的图床用。最开始尝试了PicGo+Gitee,但是发现在Typora中可以正常看图,博客里因为Gitee反外链的原因,用不了。于是就自己搭建一个图床好了。2. 图床搭建Typecho本来就是用宝塔搭的,现在再搭一次而已2.1 准备库libmagickwand兰空图床依赖PHP的imagick插件,imagick依赖这个库,因此先在Linux中安装之apt-get install libmagickwand-dev2.2 准备插件和环境登录宝塔面板安装一个PHP 8.0 及以上的版本安装好后在右侧的设置中,下载这两个插件在禁用函数中,关闭 exec、symlink等函数的禁用 注意 :这是一个危险操作,打开exec的禁用很容易让你的php被打,但是图床要求开启,只能在别的地方多注意安全了2.3 上传文件在宝塔中添加一个站点,域名一类的配置按你的配置来。PHP版本选刚刚下载好的版本。FTP不创建,数据库创建在github下载开源的兰空图床,并传到网站根目录下,解压缩unzip lsky-pro-2.1.zip 2.4 设置伪静态网站->设置中修改伪静态设置location / { try_files $uri $uri/ /index.php?$query_string; }2.5 自动配置此时访问对应域名的主页面,应该会出现运行环境检测如果没有,403了,可能是由于传文件,对应文件是root权限导致的,用宝塔面板把权限给www即可如果还有一些函数和拓展问题,按上面的步骤逐一解决下一步后,会让你配置数据库和管理员账号,数据库使用宝塔建站的数据库,管理员账号密码就是你以后上传用的账号密码。2.6 获取令牌登录,进入管理员设置页面系统设置,确保使用接口的开关是打开的到接口栏,可以看到需要一次POST生成Token,email和password就是之前配置的那个我用Postman进行post,你可以随便找个在线工具,或者用CURL、Python啥的,都行,得到的Token一会用3 PicGoPicGo是Electron写的,开箱即用,主页在PicGo挑一个正式版或者beta版本下载并安装。安装好了之后双击并不会出现页面,它会出现在任务栏里打开之后选插件设置,安装lankong插件之后编辑配置文件设置好版本和域名Token填刚刚Post得到的Token,前面加上Bearer (后面有个空格)右键任务栏图标-选择默认图床,选择lankong4 配置Typora在Typora打开偏好设置-图像上传服务选PicGo app,填好路径,点下验证图片上传选项即可。我习惯复制图片到本地,然后手动上传,原因是平时用截图比较多,如果不复制到本地直接上传的话,经常会有问题。
2023年09月07日
11 阅读
0 评论
0 点赞
2023-09-06
Rust入门笔记 5.方法和关联函数[WIP]
使用 impl "struct_name" 的方式声明关联函数struct Point { x: f64, y: f64, } impl Point { fn origin() -> Point { Point { x: 0.0, y:0.0 } } fn new(x: f64, y:f64) -> Point { Point {x:x, y:y} } }在第一个参数处声明一个Self类型的变量,以为结构创建方法self <=> self: Self &self <=> self: &Self &mut self <=> self: &mut Self // self 会拿走当前结构体实例(调用对象)的所有权,而 &self 却只会借用一个不可变引用,&mut self 会借用一个可变引用 struct Rectangle { p1: Point, p2: Point, } impl Rectangle { // 这是一个方法 // `&self` 是 `self: &Self` 的语法糖 // `Self` 是当前调用对象的类型,对于本例来说 `Self` = `Rectangle` fn perimeter(&self) -> f64 { let Point { x: x1, y: y1 } = self.p1; let Point { x: x2, y: y2 } = self.p2; 2.0 * ((x1 - x2).abs() + (y1 - y2).abs()) } }以self声明的方法会拿走调用者的所有权关联函数使用 :: 操作符来调用fn main() { let rectangle = Rectangle { // 关联函数的调用不是通过点操作符,而是使用 `::` p1: Point::origin(), p2: Point::new(3.0, 4.0), }; }方法使用 . 操作符调用println!("Rectangle perimeter: {}", rectangle.perimeter());struct Rectangle { width: u32, height: u32, } impl Rectangle { // 完成 area 方法,返回矩形 Rectangle 的面积 // fn area fn area(&self) -> u32 { self.width * self.height } } fn main() { let rect1 = Rectangle { width: 30, height: 50 }; assert_eq!(rect1.area(), 1500); }// 只填空,不要删除任何代码行! #[derive(Debug)] struct TrafficLight { color: String, } impl TrafficLight { pub fn show_state(&self) { // 如果这里使用 self 而不是 &self,就会拿走所有权 println!("the current state is {}", self.color); } } fn main() { let light = TrafficLight{ color: "red".to_owned(), }; // 不要拿走 `light` 的所有权 light.show_state(); // 否则下面代码会报错 println!("{:?}", light); }
2023年09月06日
12 阅读
0 评论
0 点赞
2023-08-30
FreeBSD Kernel-编译环境搭建
FreeBSD Kernel-编译环境搭建0 概述本文章介绍一个搭建基于Qemu的FreeBSD虚拟机、在Linux下交叉编译FreeBSD内核并替换FreeBSD内核的开发环境。1 文件准备我把以下的步骤都打包为一个docker image:yirannn/modular-os-env,如果你使用该镜像,可以略过文件准备部分1.1 FreeBSD SRC你可以在官方网站或者科大镜像下载你需要的文件,其中src.txz为FreeBSD的源码1.2 FreeBSD QCOW2你可以在官方网站或者科大镜像下载qemu可用的qcow2文件,用于作为替换内核的基础镜像1.3 编译软件包下载好文件后,你可以选择参照我的镜像Dockerfile来安装软件包。apt-get install qemu-system wget bmake gcc g++ clang-14 lld-14 libarchive-dev1.4 启动Dockerdocker run -it --name modular-os-zswap --privileged=true yirannn/modular-os-env bash如果出现 mount无权限、qemu无kvm,首先怀疑是不是privileged没打开2 编译2.1 编译命令的来源FreeBSD的源码并未直接准备好在Linux下编译,但是在FreeBSD 13之后,官方开始在macOS、Linux下进行交叉编译,并提供了Github CI进行验证。我在Action中翻到了相关的编译命令,仿照相关命令进行编译。这意味着我其实并不知道每一步具体都干了什么,如果你对此有疑问,建议可以自行查阅FreeBSD的Github Actionname: Cross-build Kernel on: push: branches: [ main, 'stable/13' ] pull_request: branches: [ main ] permissions: contents: read jobs: build: name: ${{ matrix.target_arch }} ${{ matrix.os }} (${{ matrix.compiler }}) runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: target_arch: [ amd64, aarch64 ] os: [ ubuntu-20.04, ubuntu-22.04, macos-latest ] include: # TODO: both Ubuntu and macOS have bmake packages, we should try them instead of bootstrapping our own copy. - os: ubuntu-20.04 compiler: clang-12 cross-bindir: /usr/lib/llvm-12/bin pkgs: bmake libarchive-dev clang-12 lld-12 - os: ubuntu-22.04 compiler: clang-14 cross-bindir: /usr/lib/llvm-14/bin pkgs: bmake libarchive-dev clang-14 lld-14 - os: macos-latest compiler: clang-13 cross-bindir: /usr/local/opt/llvm@13/bin pkgs: bmake libarchive llvm@13 - target_arch: amd64 target: amd64 - target_arch: aarch64 target: arm64 steps: - uses: actions/checkout@v3 - name: install packages (Ubuntu) if: runner.os == 'Linux' run: | sudo apt-get update --quiet || true sudo apt-get -yq --no-install-suggests --no-install-recommends install ${{ matrix.pkgs }} - name: install packages (macOS) if: runner.os == 'macOS' run: | brew update --quiet || true brew install ${{ matrix.pkgs }} || true - name: create environment run: | echo "GITHUB_WORKSPACE = $GITHUB_WORKSPACE" if [ -n "${{ matrix.cross-bindir }}" ]; then echo "EXTRA_BUILD_ARGS=--cross-bindir=${{ matrix.cross-bindir }}" >> $GITHUB_ENV fi mkdir -p ../build echo "MAKEOBJDIRPREFIX=${PWD%/*}/build" >> $GITHUB_ENV # heh, works on Linux/BSD/macOS ... echo "NPROC=`getconf _NPROCESSORS_ONLN 2>/dev/null || getconf NPROCESSORS_ONLN 2>/dev/null || echo 1`" >> $GITHUB_ENV - name: bootstrap bmake run: ./tools/build/make.py --debug $EXTRA_BUILD_ARGS TARGET=${{ matrix.target }} TARGET_ARCH=${{ matrix.target_arch }} -n - name: make kernel-toolchain run: ./tools/build/make.py --debug $EXTRA_BUILD_ARGS TARGET=${{ matrix.target }} TARGET_ARCH=${{ matrix.target_arch }} kernel-toolchain -s -j$NPROC -DWITH_DISK_IMAGE_TOOLS_BOOTSTRAP - name: make buildkernel run: ./tools/build/make.py --debug $EXTRA_BUILD_ARGS TARGET=${{ matrix.target }} TARGET_ARCH=${{ matrix.target_arch }} KERNCONF=GENERIC NO_MODULES=yes buildkernel -s -j$NPROC $EXTRA_MAKE_ARGS2.2 编译FreeBSD的编译需要几个环境变量,我们构建如下的目录结构parent --|-- src | |--- tools --- build | |-- obj并在parent目录下声明如下变量export BASEDIR=$(pwd) export MAKEOBJDIRPREFIX=$BASEDIR/obj这之后,进入src目录,开始编译cd $BASEDIR/src # 进入src目录 ./tools/build/make.py --debug --cross-bindir=/usr/lib/llvm-14/bin/ TARGET=amd64 TARGET_ARCH=amd64 -n # Bootstrap ./tools/build/make.py --debug --cross-bindir=/usr/lib/llvm-14/bin/ TARGET=amd64 TARGET_ARCH=amd64 kernel-toolchain -s -j32 -DWITH_DISK_IMAGE_TOOLS_BOOTSTRAP # Toolchain ./tools/build/make.py --debug --cross-bindir=/usr/lib/llvm-14/bin/ TARGET=amd64 TARGET_ARCH=amd64 KERNCONF=GENERIC NO_MODULES=yes buildkernel -s -j32 # Kernel其中 cross-bindir 指示了用于交叉编译的编译器二进制文件存放目录,TARGET和TARGET_ARCH指示了交叉编译的目标系统架构,编译好的内核在 obj/root/source/freebsd/src/amd64.amd64/sys/GENERIC/kernel.full3 内核替换3.1 准备共享区共享区是为了把宿主机编译好的 kernel.full 传递给 qemu 启动的虚拟机首先创建一块4M*1K的虚拟磁盘,用ext4格式化dd if=/dev/zero of=/opt/share.img bs=4M count=1k mkfs.ext4 /opt/share.img创建一个目录,把该虚拟磁盘文件挂到该目录,并把编译好的内核放在该目录中如果 mount 无权限,但已经在超级用户权限下了,考虑是否容器启动没有priviledgedmkdir /tmp/share mount -o loop /opt/share.img /tmp/share cp $BASEDIR/obj/root/source/freebsd/src/amd64.amd64/sys/GENERIC/kernel.full /tmp/share3.2 准备虚拟机3.2.1 启动虚拟机在第一步骤中已经下载好了qcow2在本步骤中我们进行一个使用unxz FreeBSD-12.4-RELEASE-amd64.qcow2.xz qemu-img resize FreeBSD-12.4-RELEASE-amd64.qcow2 +1G # 调整镜像大小,如果不调整,后续无法安装软件包这之后,使用qemu启动FreeBSDqemu-system-x86_64 -drive file=FreeBSD-12.4-RELEASE-amd64.qcow2,format=qcow2 -enable-kvm -hdb /opt/share.img目前qemu启动FreeBSD还必须用一个图形界面,如果使用-nographic 选项,会导致FreeBSD无法正常Boot这之后,使用root用户登录,没有密码输入uname -a 查看内核版本,可以看到我们加载的是 FreeBSD 12.4接下来挂载我们刚刚准备好的共享区pkg install sysutils/fusefs-ext2这一步需要按两次y,并有可能出现磁盘空间不足的问题。这可能是由于前步未执行扩展qcow2指令导致的3.2.2 如果空间不足怎么办关闭虚拟机,回到宿主机,尝试扩展qcow2文件qemu-img resize FreeBSD-12.4-RELEASE-amd64.qcow2 +1G重新用刚刚的命令启动qemu,在FreeBSD中gpart show可以看到freebsd-ufs的空间情况和分区号使用gpart扩展ufs分区gpart resize -i 4 -a 4k -s 5G ada0 growfs /dev/gpt/rootfs重新安装fusefs-ext2模块3.2.3 挂载使用camcontrol命令查看当前系统的硬件设备第一块盘ada0是启动的系统盘,第二块是我们在qemu中用hdb参数挂上去的共享盘用fuse-ext2对这个盘进行映射kldload fuse.ko # 如果不注册,每次用都得加载一下 mkdir /share fuse-ext2 /dev/ada1 /share ls /share把kernel替换掉cd /boot/kernel mv kernel kernel.old cp /share/kernel.full ./kernel reboot等待系统重启,重新uname -a此时可以看到内核已经更新到我们编译的13.2
2023年08月30日
34 阅读
0 评论
0 点赞
1
2
...
4