OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [fs/] [sysfs/] [inode.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * fs/sysfs/inode.c - basic sysfs inode and dentry operations
3
 *
4
 * Copyright (c) 2001-3 Patrick Mochel
5
 * Copyright (c) 2007 SUSE Linux Products GmbH
6
 * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
7
 *
8
 * This file is released under the GPLv2.
9
 *
10
 * Please see Documentation/filesystems/sysfs.txt for more information.
11
 */
12
 
13
#undef DEBUG 
14
 
15
#include <linux/pagemap.h>
16
#include <linux/namei.h>
17
#include <linux/backing-dev.h>
18
#include <linux/capability.h>
19
#include <linux/errno.h>
20
#include <linux/sched.h>
21
#include "sysfs.h"
22
 
23
extern struct super_block * sysfs_sb;
24
 
25
static const struct address_space_operations sysfs_aops = {
26
        .readpage       = simple_readpage,
27
        .write_begin    = simple_write_begin,
28
        .write_end      = simple_write_end,
29
};
30
 
31
static struct backing_dev_info sysfs_backing_dev_info = {
32
        .ra_pages       = 0,     /* No readahead */
33
        .capabilities   = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
34
};
35
 
36
static const struct inode_operations sysfs_inode_operations ={
37
        .setattr        = sysfs_setattr,
38
};
39
 
40
int __init sysfs_inode_init(void)
41
{
42
        return bdi_init(&sysfs_backing_dev_info);
43
}
44
 
45
int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
46
{
47
        struct inode * inode = dentry->d_inode;
48
        struct sysfs_dirent * sd = dentry->d_fsdata;
49
        struct iattr * sd_iattr;
50
        unsigned int ia_valid = iattr->ia_valid;
51
        int error;
52
 
53
        if (!sd)
54
                return -EINVAL;
55
 
56
        sd_iattr = sd->s_iattr;
57
 
58
        error = inode_change_ok(inode, iattr);
59
        if (error)
60
                return error;
61
 
62
        error = inode_setattr(inode, iattr);
63
        if (error)
64
                return error;
65
 
66
        if (!sd_iattr) {
67
                /* setting attributes for the first time, allocate now */
68
                sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL);
69
                if (!sd_iattr)
70
                        return -ENOMEM;
71
                /* assign default attributes */
72
                sd_iattr->ia_mode = sd->s_mode;
73
                sd_iattr->ia_uid = 0;
74
                sd_iattr->ia_gid = 0;
75
                sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME;
76
                sd->s_iattr = sd_iattr;
77
        }
78
 
79
        /* attributes were changed atleast once in past */
80
 
81
        if (ia_valid & ATTR_UID)
82
                sd_iattr->ia_uid = iattr->ia_uid;
83
        if (ia_valid & ATTR_GID)
84
                sd_iattr->ia_gid = iattr->ia_gid;
85
        if (ia_valid & ATTR_ATIME)
86
                sd_iattr->ia_atime = timespec_trunc(iattr->ia_atime,
87
                                                inode->i_sb->s_time_gran);
88
        if (ia_valid & ATTR_MTIME)
89
                sd_iattr->ia_mtime = timespec_trunc(iattr->ia_mtime,
90
                                                inode->i_sb->s_time_gran);
91
        if (ia_valid & ATTR_CTIME)
92
                sd_iattr->ia_ctime = timespec_trunc(iattr->ia_ctime,
93
                                                inode->i_sb->s_time_gran);
94
        if (ia_valid & ATTR_MODE) {
95
                umode_t mode = iattr->ia_mode;
96
 
97
                if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
98
                        mode &= ~S_ISGID;
99
                sd_iattr->ia_mode = sd->s_mode = mode;
100
        }
101
 
102
        return error;
103
}
104
 
105
static inline void set_default_inode_attr(struct inode * inode, mode_t mode)
106
{
107
        inode->i_mode = mode;
108
        inode->i_uid = 0;
109
        inode->i_gid = 0;
110
        inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
111
}
112
 
113
static inline void set_inode_attr(struct inode * inode, struct iattr * iattr)
114
{
115
        inode->i_mode = iattr->ia_mode;
116
        inode->i_uid = iattr->ia_uid;
117
        inode->i_gid = iattr->ia_gid;
118
        inode->i_atime = iattr->ia_atime;
119
        inode->i_mtime = iattr->ia_mtime;
120
        inode->i_ctime = iattr->ia_ctime;
121
}
122
 
123
 
124
/*
125
 * sysfs has a different i_mutex lock order behavior for i_mutex than other
126
 * filesystems; sysfs i_mutex is called in many places with subsystem locks
127
 * held. At the same time, many of the VFS locking rules do not apply to
128
 * sysfs at all (cross directory rename for example). To untangle this mess
129
 * (which gives false positives in lockdep), we're giving sysfs inodes their
130
 * own class for i_mutex.
131
 */
132
static struct lock_class_key sysfs_inode_imutex_key;
133
 
134
static int sysfs_count_nlink(struct sysfs_dirent *sd)
135
{
136
        struct sysfs_dirent *child;
137
        int nr = 0;
138
 
139
        for (child = sd->s_dir.children; child; child = child->s_sibling)
140
                if (sysfs_type(child) == SYSFS_DIR)
141
                        nr++;
142
 
143
        return nr + 2;
144
}
145
 
146
static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
147
{
148
        struct bin_attribute *bin_attr;
149
 
150
        inode->i_blocks = 0;
151
        inode->i_mapping->a_ops = &sysfs_aops;
152
        inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
153
        inode->i_op = &sysfs_inode_operations;
154
        inode->i_ino = sd->s_ino;
155
        lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);
156
 
157
        if (sd->s_iattr) {
158
                /* sysfs_dirent has non-default attributes
159
                 * get them for the new inode from persistent copy
160
                 * in sysfs_dirent
161
                 */
162
                set_inode_attr(inode, sd->s_iattr);
163
        } else
164
                set_default_inode_attr(inode, sd->s_mode);
165
 
166
 
167
        /* initialize inode according to type */
168
        switch (sysfs_type(sd)) {
169
        case SYSFS_DIR:
170
                inode->i_op = &sysfs_dir_inode_operations;
171
                inode->i_fop = &sysfs_dir_operations;
172
                inode->i_nlink = sysfs_count_nlink(sd);
173
                break;
174
        case SYSFS_KOBJ_ATTR:
175
                inode->i_size = PAGE_SIZE;
176
                inode->i_fop = &sysfs_file_operations;
177
                break;
178
        case SYSFS_KOBJ_BIN_ATTR:
179
                bin_attr = sd->s_bin_attr.bin_attr;
180
                inode->i_size = bin_attr->size;
181
                inode->i_fop = &bin_fops;
182
                break;
183
        case SYSFS_KOBJ_LINK:
184
                inode->i_op = &sysfs_symlink_inode_operations;
185
                break;
186
        default:
187
                BUG();
188
        }
189
 
190
        unlock_new_inode(inode);
191
}
192
 
193
/**
194
 *      sysfs_get_inode - get inode for sysfs_dirent
195
 *      @sd: sysfs_dirent to allocate inode for
196
 *
197
 *      Get inode for @sd.  If such inode doesn't exist, a new inode
198
 *      is allocated and basics are initialized.  New inode is
199
 *      returned locked.
200
 *
201
 *      LOCKING:
202
 *      Kernel thread context (may sleep).
203
 *
204
 *      RETURNS:
205
 *      Pointer to allocated inode on success, NULL on failure.
206
 */
207
struct inode * sysfs_get_inode(struct sysfs_dirent *sd)
208
{
209
        struct inode *inode;
210
 
211
        inode = iget_locked(sysfs_sb, sd->s_ino);
212
        if (inode && (inode->i_state & I_NEW))
213
                sysfs_init_inode(sd, inode);
214
 
215
        return inode;
216
}
217
 
218
int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name)
219
{
220
        struct sysfs_addrm_cxt acxt;
221
        struct sysfs_dirent *sd;
222
 
223
        if (!dir_sd)
224
                return -ENOENT;
225
 
226
        sysfs_addrm_start(&acxt, dir_sd);
227
 
228
        sd = sysfs_find_dirent(dir_sd, name);
229
        if (sd)
230
                sysfs_remove_one(&acxt, sd);
231
 
232
        sysfs_addrm_finish(&acxt);
233
 
234
        if (sd)
235
                return 0;
236
        else
237
                return -ENOENT;
238
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.