您当前的位置:首页 > IT编程 > C++
| C语言 | Java | VB | VC | python | Android | TensorFlow | C++ | oracle | 学术与代码 | cnn卷积神经网络 | gnn | 图像修复 | Keras | 数据集 | Neo4j | 自然语言处理 | 深度学习 | 医学CAD | 医学影像 | 超参数 | pointnet | pytorch | 异常检测 | Transformers | 情感分类 | 知识图谱 |

自学教程:C++ truncate_pagecache函数代码示例

51自学网 2021-06-03 08:59:08
  C++
这篇教程C++ truncate_pagecache函数代码示例写得很实用,希望能帮到您。

本文整理汇总了C++中truncate_pagecache函数的典型用法代码示例。如果您正苦于以下问题:C++ truncate_pagecache函数的具体用法?C++ truncate_pagecache怎么用?C++ truncate_pagecache使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。

在下文中一共展示了truncate_pagecache函数的17个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的C++代码示例。

示例1: fuse_change_attributes

void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,			    u64 attr_valid, u64 attr_version){	struct fuse_conn *fc = get_fuse_conn(inode);	struct fuse_inode *fi = get_fuse_inode(inode);	loff_t oldsize;	spin_lock(&fc->lock);	if (attr_version != 0 && fi->attr_version > attr_version) {		spin_unlock(&fc->lock);		return;	}	fuse_change_attributes_common(inode, attr, attr_valid);	oldsize = inode->i_size;	i_size_write(inode, attr->size);	spin_unlock(&fc->lock);	if (S_ISREG(inode->i_mode) && oldsize != attr->size) {		lock_system_sleep();		truncate_pagecache(inode, oldsize, attr->size);		invalidate_inode_pages2(inode->i_mapping);		unlock_system_sleep();	}}
开发者ID:Red680812,项目名称:DNA_kitkat,代码行数:26,


示例2: fuse_change_attributes

void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,                            u64 attr_valid, u64 attr_version){    struct fuse_conn *fc = get_fuse_conn(inode);    struct fuse_inode *fi = get_fuse_inode(inode);    loff_t oldsize;    spin_lock(&fc->lock);    if ((attr_version != 0 && fi->attr_version > attr_version) ||            test_bit(FUSE_I_SIZE_UNSTABLE, &fi->state)) {        spin_unlock(&fc->lock);        return;    }    fuse_change_attributes_common(inode, attr, attr_valid);    oldsize = inode->i_size;    i_size_write(inode, attr->size);    spin_unlock(&fc->lock);    if (S_ISREG(inode->i_mode) && oldsize != attr->size) {        truncate_pagecache(inode, oldsize, attr->size);        invalidate_inode_pages2(inode->i_mapping);    }}
开发者ID:aexon,项目名称:DORIMANX_LG_STOCK_LP_KERNEL,代码行数:25,


示例3: test

void test(void){   struct inode inode;   loff_t oldSize = 0;   loff_t newSize = 4096;   truncate_pagecache(&inode, oldSize, newSize);}
开发者ID:AlissonGiron,项目名称:open-vm-tools,代码行数:8,


示例4: truncate_setsize

void truncate_setsize(struct inode *inode, loff_t newsize){	loff_t oldsize = inode->i_size;	inode->i_size = newsize;	if (newsize < oldsize)		truncate_pagecache(inode, oldsize, newsize);}
开发者ID:AbhijeetPawar,项目名称:tux3,代码行数:8,


示例5: ext2_write_failed

static void ext2_write_failed(struct address_space *mapping, loff_t to){	struct inode *inode = mapping->host;	if (to > inode->i_size) {		truncate_pagecache(inode, inode->i_size);		ext2_truncate_blocks(inode, inode->i_size);	}}
开发者ID:aejsmith,项目名称:linux,代码行数:9,


示例6: nilfs_write_failed

void nilfs_write_failed(struct address_space *mapping, loff_t to){	struct inode *inode = mapping->host;	if (to > inode->i_size) {		truncate_pagecache(inode, inode->i_size);		nilfs_truncate(inode);	}}
开发者ID:battahma,项目名称:cs444,代码行数:9,


示例7: hfsplus_write_failed

static void hfsplus_write_failed(struct address_space *mapping, loff_t to){	struct inode *inode = mapping->host;	if (to > inode->i_size) {		truncate_pagecache(inode, inode->i_size);		hfsplus_file_truncate(inode);	}}
开发者ID:a2hojsjsjs,项目名称:linux,代码行数:9,


示例8: truncate_setsize

/** * truncate_setsize - update inode and pagecache for a new file size * @inode: inode * @newsize: new file size * * truncate_setsize updates i_size and performs pagecache truncation (if * necessary) to @newsize. It will be typically be called from the filesystem's * setattr function when ATTR_SIZE is passed in. * * Must be called with a lock serializing truncates and writes (generally * i_mutex but e.g. xfs uses a different lock) and before all filesystem * specific block truncation has been performed. */void truncate_setsize(struct inode *inode, loff_t newsize){    loff_t oldsize = inode->i_size;    i_size_write(inode, newsize);    if (newsize > oldsize)        pagecache_isize_extended(inode, oldsize, newsize);    truncate_pagecache(inode, newsize);}
开发者ID:stefanberger,项目名称:linux-tpmdd,代码行数:22,


示例9: sfs_write_failed

static void sfs_write_failed(struct address_space *mapping, loff_t to){	struct inode *inode = mapping->host;	pr_debug("sfs_write_failed called./n");	if (to > inode->i_size) {		truncate_pagecache(inode, inode->i_size);		sfs_truncate(inode);	}	}
开发者ID:nosway,项目名称:sfs,代码行数:10,


示例10: fuse_change_attributes

void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,			    u64 attr_valid, u64 attr_version){	struct fuse_conn *fc = get_fuse_conn(inode);	struct fuse_inode *fi = get_fuse_inode(inode);	bool is_wb = fc->writeback_cache;	loff_t oldsize;	struct timespec old_mtime;	spin_lock(&fc->lock);	if ((attr_version != 0 && fi->attr_version > attr_version) ||	    test_bit(FUSE_I_SIZE_UNSTABLE, &fi->state)) {		spin_unlock(&fc->lock);		return;	}	old_mtime = inode->i_mtime;	fuse_change_attributes_common(inode, attr, attr_valid);	oldsize = inode->i_size;	/*	 * In case of writeback_cache enabled, the cached writes beyond EOF	 * extend local i_size without keeping userspace server in sync. So,	 * attr->size coming from server can be stale. We cannot trust it.	 */	if (!is_wb || !S_ISREG(inode->i_mode))		i_size_write(inode, attr->size);	spin_unlock(&fc->lock);	if (!is_wb && S_ISREG(inode->i_mode)) {		bool inval = false;		if (oldsize != attr->size) {			truncate_pagecache(inode, attr->size);			inval = true;		} else if (fc->auto_inval_data) {			struct timespec new_mtime = {				.tv_sec = attr->mtime,				.tv_nsec = attr->mtimensec,			};			/*			 * Auto inval mode also checks and invalidates if mtime			 * has changed.			 */			if (!timespec_equal(&old_mtime, &new_mtime))				inval = true;		}		if (inval)			invalidate_inode_pages2(inode->i_mapping);	}}
开发者ID:acton393,项目名称:linux,代码行数:53,


示例11: fuse_change_attributes

void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,			    u64 attr_valid, u64 attr_version){	struct fuse_conn *fc = get_fuse_conn(inode);	struct fuse_inode *fi = get_fuse_inode(inode);	loff_t oldsize;	struct timespec old_mtime;	spin_lock(&fc->lock);	if ((attr_version != 0 && fi->attr_version > attr_version) ||	    test_bit(FUSE_I_SIZE_UNSTABLE, &fi->state)) {		spin_unlock(&fc->lock);		return;	}	old_mtime = inode->i_mtime;	fuse_change_attributes_common(inode, attr, attr_valid);	oldsize = inode->i_size;	i_size_write(inode, attr->size);	spin_unlock(&fc->lock);	if (S_ISREG(inode->i_mode)) {		bool inval = false;		if (oldsize != attr->size) {			truncate_pagecache(inode, oldsize, attr->size);			inval = true;		} else if (fc->auto_inval_data) {			struct timespec new_mtime = {				.tv_sec = attr->mtime,				.tv_nsec = attr->mtimensec,			};			/*			 * Auto inval mode also checks and invalidates if mtime			 * has changed.			 */			if (!timespec_equal(&old_mtime, &new_mtime))				inval = true;		}		if (inval)			invalidate_inode_pages2(inode->i_mapping);	}}
开发者ID:Jlsmily,项目名称:android_kernel_meilan2,代码行数:46,


示例12: vvp_do_vmtruncate

static int vvp_do_vmtruncate(struct inode *inode, size_t size){	int     result;	loff_t oldsize;	/*	 * Only ll_inode_size_lock is taken at this level.	 */	ll_inode_size_lock(inode);	result = inode_newsize_ok(inode, size);	if (result < 0) {		ll_inode_size_unlock(inode);		return result;	}	oldsize = inode->i_size;	i_size_write(inode, size);	truncate_pagecache(inode, oldsize, size);	ll_inode_size_unlock(inode);	return result;}
开发者ID:walgenbach,项目名称:lustre-release,代码行数:21,


示例13: f2fs_collapse_range

static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len){    pgoff_t pg_start, pg_end;    loff_t new_size;    int ret;    if (!S_ISREG(inode->i_mode))        return -EINVAL;    if (offset + len >= i_size_read(inode))        return -EINVAL;    /* collapse range should be aligned to block size of f2fs. */    if (offset & (F2FS_BLKSIZE - 1) || len & (F2FS_BLKSIZE - 1))        return -EINVAL;    pg_start = offset >> PAGE_CACHE_SHIFT;    pg_end = (offset + len) >> PAGE_CACHE_SHIFT;    /* write out all dirty pages from offset */    ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);    if (ret)        return ret;    truncate_pagecache(inode, offset);    ret = f2fs_do_collapse(inode, pg_start, pg_end);    if (ret)        return ret;    new_size = i_size_read(inode) - len;    ret = truncate_blocks(inode, new_size, true);    if (!ret)        i_size_write(inode, new_size);    return ret;}
开发者ID:infidel,项目名称:linux,代码行数:38,


示例14: fuse_do_setattr

//.........这里部分代码省略.........	struct fuse_attr_out outarg;	bool is_truncate = false;	bool is_wb = fc->writeback_cache;	loff_t oldsize;	int err;	bool trust_local_cmtime = is_wb && S_ISREG(inode->i_mode);	if (!fc->default_permissions)		attr->ia_valid |= ATTR_FORCE;	err = setattr_prepare(dentry, attr);	if (err)		return err;	if (attr->ia_valid & ATTR_OPEN) {		if (fc->atomic_o_trunc)			return 0;		file = NULL;	}	if (attr->ia_valid & ATTR_SIZE)		is_truncate = true;	if (is_truncate) {		fuse_set_nowrite(inode);		set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);		if (trust_local_cmtime && attr->ia_size != inode->i_size)			attr->ia_valid |= ATTR_MTIME | ATTR_CTIME;	}	memset(&inarg, 0, sizeof(inarg));	memset(&outarg, 0, sizeof(outarg));	iattr_to_fattr(attr, &inarg, trust_local_cmtime);	if (file) {		struct fuse_file *ff = file->private_data;		inarg.valid |= FATTR_FH;		inarg.fh = ff->fh;	}	if (attr->ia_valid & ATTR_SIZE) {		/* For mandatory locking in truncate */		inarg.valid |= FATTR_LOCKOWNER;		inarg.lock_owner = fuse_lock_owner_id(fc, current->files);	}	fuse_setattr_fill(fc, &args, inode, &inarg, &outarg);	err = fuse_simple_request(fc, &args);	if (err) {		if (err == -EINTR)			fuse_invalidate_attr(inode);		goto error;	}	if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {		make_bad_inode(inode);		err = -EIO;		goto error;	}	spin_lock(&fc->lock);	/* the kernel maintains i_mtime locally */	if (trust_local_cmtime) {		if (attr->ia_valid & ATTR_MTIME)			inode->i_mtime = attr->ia_mtime;		if (attr->ia_valid & ATTR_CTIME)			inode->i_ctime = attr->ia_ctime;		/* FIXME: clear I_DIRTY_SYNC? */	}	fuse_change_attributes_common(inode, &outarg.attr,				      attr_timeout(&outarg));	oldsize = inode->i_size;	/* see the comment in fuse_change_attributes() */	if (!is_wb || is_truncate || !S_ISREG(inode->i_mode))		i_size_write(inode, outarg.attr.size);	if (is_truncate) {		/* NOTE: this may release/reacquire fc->lock */		__fuse_release_nowrite(inode);	}	spin_unlock(&fc->lock);	/*	 * Only call invalidate_inode_pages2() after removing	 * FUSE_NOWRITE, otherwise fuse_launder_page() would deadlock.	 */	if ((is_truncate || !is_wb) &&	    S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) {		truncate_pagecache(inode, outarg.attr.size);		invalidate_inode_pages2(inode->i_mapping);	}	clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);	return 0;error:	if (is_truncate)		fuse_release_nowrite(inode);	clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);	return err;}
开发者ID:mkrufky,项目名称:linux,代码行数:101,


示例15: f2fs_insert_range

static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len){	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);	pgoff_t pg_start, pg_end, delta, nrpages, idx;	loff_t new_size;	int ret;	if (!S_ISREG(inode->i_mode))		return -EINVAL;	new_size = i_size_read(inode) + len;	if (new_size > inode->i_sb->s_maxbytes)		return -EFBIG;	if (offset >= i_size_read(inode))		return -EINVAL;	/* insert range should be aligned to block size of f2fs. */	if (offset & (F2FS_BLKSIZE - 1) || len & (F2FS_BLKSIZE - 1))		return -EINVAL;	f2fs_balance_fs(sbi);	if (f2fs_has_inline_data(inode)) {		ret = f2fs_convert_inline_inode(inode);		if (ret)			return ret;	}	ret = truncate_blocks(inode, i_size_read(inode), true);	if (ret)		return ret;	/* write out all dirty pages from offset */	ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);	if (ret)		return ret;	truncate_pagecache(inode, 0, offset);	pg_start = offset >> PAGE_CACHE_SHIFT;	pg_end = (offset + len) >> PAGE_CACHE_SHIFT;	delta = pg_end - pg_start;	nrpages = (i_size_read(inode) + PAGE_SIZE - 1) / PAGE_SIZE;	for (idx = nrpages - 1; idx >= pg_start && idx != -1; idx--) {		struct dnode_of_data dn;		struct page *ipage;		block_t new_addr, old_addr;		f2fs_lock_op(sbi);		set_new_dnode(&dn, inode, NULL, NULL, 0);		ret = get_dnode_of_data(&dn, idx, LOOKUP_NODE_RA);		if (ret && ret != -ENOENT) {			goto out;		} else if (ret == -ENOENT) {			goto next;		} else if (dn.data_blkaddr == NULL_ADDR) {			f2fs_put_dnode(&dn);			goto next;		} else {			new_addr = dn.data_blkaddr;			truncate_data_blocks_range(&dn, 1);			f2fs_put_dnode(&dn);		}		ipage = get_node_page(sbi, inode->i_ino);		if (IS_ERR(ipage)) {			ret = PTR_ERR(ipage);			goto out;		}		set_new_dnode(&dn, inode, ipage, NULL, 0);		ret = f2fs_reserve_block(&dn, idx + delta);		if (ret)			goto out;		old_addr = dn.data_blkaddr;		f2fs_bug_on(sbi, old_addr != NEW_ADDR);		if (new_addr != NEW_ADDR) {			struct node_info ni;			get_node_info(sbi, dn.nid, &ni);			f2fs_replace_block(sbi, &dn, old_addr, new_addr,							ni.version, true);		}		f2fs_put_dnode(&dn);next:		f2fs_unlock_op(sbi);	}	i_size_write(inode, new_size);	return 0;out:	f2fs_unlock_op(sbi);	return ret;}
开发者ID:handelxh,项目名称:ONEPLUS2RAZOR,代码行数:99,


示例16: fuse_do_setattr

//.........这里部分代码省略.........	struct fuse_attr_out outarg;	bool is_truncate = false;	int is_wb = fc->writeback_cache;	loff_t oldsize;	int err;	bool trust_local_mtime = is_wb && S_ISREG(inode->i_mode);	if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {		err = inode_change_ok(inode, attr);		if (err)			return err;	}	if ((attr->ia_valid & ATTR_OPEN) && fc->atomic_o_trunc)		return 0;	if (attr->ia_valid & ATTR_SIZE) {		err = inode_newsize_ok(inode, attr->ia_size);		if (err)			return err;		is_truncate = true;	}	req = fuse_get_req_nopages(fc);	if (IS_ERR(req))		return PTR_ERR(req);	if (is_truncate) {		fuse_set_nowrite(inode);		set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);	}	memset(&inarg, 0, sizeof(inarg));	memset(&outarg, 0, sizeof(outarg));	iattr_to_fattr(attr, &inarg, trust_local_mtime);	if (file) {		struct fuse_file *ff = file->private_data;		inarg.valid |= FATTR_FH;		inarg.fh = ff->fh;	}	if (attr->ia_valid & ATTR_SIZE) {		/* For mandatory locking in truncate */		inarg.valid |= FATTR_LOCKOWNER;		inarg.lock_owner = fuse_lock_owner_id(fc, current->files);	}	fuse_setattr_fill(fc, req, inode, &inarg, &outarg);	fuse_request_send(fc, req);	err = req->out.h.error;	fuse_put_request(fc, req);	if (err) {		if (err == -EINTR)			fuse_invalidate_attr(inode);		goto error;	}	if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {		make_bad_inode(inode);		err = -EIO;		goto error;	}	spin_lock(&fc->lock);	/* the kernel maintains i_mtime locally */	if (trust_local_mtime && (attr->ia_valid & ATTR_MTIME)) {		inode->i_mtime = attr->ia_mtime;		clear_bit(FUSE_I_MTIME_DIRTY, &fi->state);	}	fuse_change_attributes_common(inode, &outarg.attr,				      attr_timeout(&outarg));	oldsize = inode->i_size;	if (!is_wb || is_truncate || !S_ISREG(inode->i_mode))		i_size_write(inode, outarg.attr.size);	if (is_truncate) {		/* NOTE: this may release/reacquire fc->lock */		__fuse_release_nowrite(inode);	}	spin_unlock(&fc->lock);	/*	 * Only call invalidate_inode_pages2() after removing	 * FUSE_NOWRITE, otherwise fuse_launder_page() would deadlock.	 */	if ((is_truncate || !is_wb) &&	    S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) {		truncate_pagecache(inode, oldsize, outarg.attr.size);		invalidate_inode_pages2(inode->i_mapping);	}	clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);	return 0;error:	if (is_truncate)		fuse_release_nowrite(inode);	clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);	return err;}
开发者ID:miurahr,项目名称:fuse-centos6-kernel-backport,代码行数:101,


示例17: sdcardfs_setattr

static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia){	int err = 0;	struct dentry *lower_dentry;	struct inode *inode;	struct inode *lower_inode;	struct path lower_path;	struct iattr lower_ia;	struct dentry *parent;	inode = dentry->d_inode;	/*	 * Check if user has permission to change inode.  We don't check if	 * this user can change the lower inode: that should happen when	 * calling notify_change on the lower inode.	 */	err = inode_change_ok(inode, ia);	/* no vfs_XXX operations required, cred overriding will be skipped. wj*/	if (!err) {		/* check the Android group ID */		parent = dget_parent(dentry);		if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name)) {			printk(KERN_INFO "%s: need to check the caller's gid in packages.list/n" 							 "  dentry: %s, task:%s/n",							 __func__, dentry->d_name.name, current->comm);			err = -EACCES;		}		dput(parent);	} 	if (err)		goto out_err;	sdcardfs_get_lower_path(dentry, &lower_path);	lower_dentry = lower_path.dentry;	lower_inode = sdcardfs_lower_inode(inode);	/* prepare our own lower struct iattr (with the lower file) */	memcpy(&lower_ia, ia, sizeof(lower_ia));	if (ia->ia_valid & ATTR_FILE)		lower_ia.ia_file = sdcardfs_lower_file(ia->ia_file);	lower_ia.ia_valid &= ~(ATTR_UID | ATTR_GID | ATTR_MODE);	/*	 * If shrinking, first truncate upper level to cancel writing dirty	 * pages beyond the new eof; and also if its' maxbytes is more	 * limiting (fail with -EFBIG before making any change to the lower	 * level).  There is no need to vmtruncate the upper level	 * afterwards in the other cases: we fsstack_copy_inode_size from	 * the lower level.	 */	if (ia->ia_valid & ATTR_SIZE) {		loff_t oldsize;		err = inode_newsize_ok(inode, ia->ia_size);		if (err)			goto out;		/* This code from truncate_setsize(). We need to add spin_lock		 * to avoid race condition with fsstack_copy_inode_size() */		oldsize = i_size_read(inode);		if (sizeof(ia->ia_size) > sizeof(long))			spin_lock(&inode->i_lock);		i_size_write(inode, ia->ia_size);		if (sizeof(ia->ia_size) > sizeof(long))			spin_unlock(&inode->i_lock);		if (ia->ia_size > oldsize)			pagecache_isize_extended(inode, oldsize, ia->ia_size);		truncate_pagecache(inode, oldsize, ia->ia_size);	}	/*	 * mode change is for clearing setuid/setgid bits. Allow lower fs	 * to interpret this in its own way.	 */	if (lower_ia.ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))		lower_ia.ia_valid &= ~ATTR_MODE;	/* notify the (possibly copied-up) lower inode */	/*	 * Note: we use lower_dentry->d_inode, because lower_inode may be	 * unlinked (no inode->i_sb and i_ino==0.  This happens if someone	 * tries to open(), unlink(), then ftruncate() a file.	 */	mutex_lock(&lower_dentry->d_inode->i_mutex);	err = notify_change(lower_dentry, &lower_ia); /* note: lower_ia */	mutex_unlock(&lower_dentry->d_inode->i_mutex);	if (err)		goto out;	/* get attributes from the lower inode, i_mutex held */	sdcardfs_copy_inode_attr(inode, lower_inode);	/* update derived permission of the upper inode */	fix_derived_permission(inode);	/*	 * Not running fsstack_copy_inode_size(inode, lower_inode), because	 * VFS should update our inode size, and notify_change on	 * lower_inode should update its size.//.........这里部分代码省略.........
开发者ID:Mortifix,项目名称:SM-G920T,代码行数:101,



注:本文中的truncate_pagecache函数示例整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。


C++ truncate_setsize函数代码示例
C++ truncate_inode_pages函数代码示例
万事OK自学网:51自学网_软件自学网_CAD自学网自学excel、自学PS、自学CAD、自学C语言、自学css3实例,是一个通过网络自主学习工作技能的自学平台,网友喜欢的软件自学网站。