fs/attr.c

Source file repositories/reference/linux-study-clean/fs/attr.c

File Facts

System
Linux kernel
Corpus path
fs/attr.c
Extension
.c
Size
17545 bytes
Lines
568
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

if (!inode_owner_or_capable(idmap, inode)) {
			error = inode_permission(idmap, inode, MAY_WRITE);
			if (error)
				return error;
		}
	}
	return 0;
}
EXPORT_SYMBOL(may_setattr);

/**
 * notify_change - modify attributes of a filesystem object
 * @idmap:	idmap of the mount the inode was found from
 * @dentry:	object affected
 * @attr:	new attributes
 * @delegated_inode: returns inode, if the inode is delegated
 *
 * The caller must hold the i_rwsem exclusively on the affected object.
 *
 * If notify_change discovers a delegation in need of breaking,
 * it will return -EWOULDBLOCK and return a reference to the inode in
 * delegated_inode.  The caller should then break the delegation and
 * retry.  Because breaking a delegation may take a long time, the
 * caller should drop the i_rwsem before doing so.
 *
 * Alternatively, a caller may pass NULL for delegated_inode.  This may
 * be appropriate for callers that expect the underlying filesystem not
 * to be NFS exported.  Also, passing NULL is fine for callers holding
 * the file open for write, as there can be no conflicting delegation in
 * that case.
 *
 * If the inode has been found through an idmapped mount the idmap of
 * the vfsmount must be passed through @idmap. This function will then
 * take care to map the inode according to @idmap before checking
 * permissions. On non-idmapped mounts or if permission checking is to be
 * performed on the raw inode simply pass @nop_mnt_idmap.
 */
int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
		  struct iattr *attr, struct delegated_inode *delegated_inode)
{
	struct inode *inode = dentry->d_inode;
	umode_t mode = inode->i_mode;
	int error;
	struct timespec64 now;
	unsigned int ia_valid = attr->ia_valid;

	WARN_ON_ONCE(!inode_is_locked(inode));

	error = may_setattr(idmap, inode, ia_valid);
	if (error)
		return error;

	if ((ia_valid & ATTR_MODE)) {
		/*
		 * Don't allow changing the mode of symlinks:
		 *
		 * (1) The vfs doesn't take the mode of symlinks into account
		 *     during permission checking.
		 * (2) This has never worked correctly. Most major filesystems
		 *     did return EOPNOTSUPP due to interactions with POSIX ACLs
		 *     but did still updated the mode of the symlink.
		 *     This inconsistency led system call wrapper providers such
		 *     as libc to block changing the mode of symlinks with
		 *     EOPNOTSUPP already.
		 * (3) To even do this in the first place one would have to use
		 *     specific file descriptors and quite some effort.
		 */
		if (S_ISLNK(inode->i_mode))
			return -EOPNOTSUPP;

		/* Flag setting protected by i_rwsem */
		if (is_sxid(attr->ia_mode))
			inode->i_flags &= ~S_NOSEC;
	}

	now = current_time(inode);

	if (ia_valid & ATTR_ATIME_SET)
		attr->ia_atime = timestamp_truncate(attr->ia_atime, inode);
	else
		attr->ia_atime = now;
	if (ia_valid & ATTR_CTIME_SET)
		attr->ia_ctime = timestamp_truncate(attr->ia_ctime, inode);
	else
		attr->ia_ctime = now;
	if (ia_valid & ATTR_MTIME_SET)
		attr->ia_mtime = timestamp_truncate(attr->ia_mtime, inode);
	else
		attr->ia_mtime = now;

Annotation

Implementation Notes