diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-25 17:17:51 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-25 17:17:51 +0200 |
commit | f16a5e347835c6a0ba958535cf6e6c89d50463b8 (patch) | |
tree | 41d2e7784f57212a3f910690e00dcd1707a7e47f /fs/gfs2 | |
parent | Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs (diff) | |
parent | GFS2: Fix permissions checking for setflags ioctl() (diff) | |
download | linux-f16a5e347835c6a0ba958535cf6e6c89d50463b8.tar.xz linux-f16a5e347835c6a0ba958535cf6e6c89d50463b8.zip |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-fixes
* git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-fixes:
GFS2: Fix permissions checking for setflags ioctl()
GFS2: Don't "get" xattrs for ACLs when ACLs are turned off
GFS2: Rework reclaiming unlinked dinodes
Diffstat (limited to 'fs/gfs2')
-rw-r--r-- | fs/gfs2/acl.c | 4 | ||||
-rw-r--r-- | fs/gfs2/file.c | 7 | ||||
-rw-r--r-- | fs/gfs2/inode.c | 54 | ||||
-rw-r--r-- | fs/gfs2/inode.h | 3 | ||||
-rw-r--r-- | fs/gfs2/log.c | 2 | ||||
-rw-r--r-- | fs/gfs2/log.h | 29 | ||||
-rw-r--r-- | fs/gfs2/rgrp.c | 20 |
7 files changed, 65 insertions, 54 deletions
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 9fb76b0a0485..48171f4c943d 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c @@ -236,10 +236,14 @@ static int gfs2_xattr_system_get(struct dentry *dentry, const char *name, void *buffer, size_t size, int xtype) { struct inode *inode = dentry->d_inode; + struct gfs2_sbd *sdp = GFS2_SB(inode); struct posix_acl *acl; int type; int error; + if (!sdp->sd_args.ar_posix_acl) + return -EOPNOTSUPP; + type = gfs2_acl_type(name); if (type < 0) return type; diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index e6dd2aec6f82..b20bfcc9fa2d 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -218,6 +218,11 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) if (error) goto out_drop_write; + error = -EACCES; + if (!is_owner_or_cap(inode)) + goto out; + + error = 0; flags = ip->i_diskflags; new_flags = (flags & ~mask) | (reqflags & mask); if ((new_flags ^ flags) == 0) @@ -275,8 +280,10 @@ static int gfs2_set_flags(struct file *filp, u32 __user *ptr) { struct inode *inode = filp->f_path.dentry->d_inode; u32 fsflags, gfsflags; + if (get_user(fsflags, ptr)) return -EFAULT; + gfsflags = fsflags_cvt(fsflags_to_gfs2, fsflags); if (!S_ISDIR(inode->i_mode)) { if (gfsflags & GFS2_DIF_INHERIT_JDATA) diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 51d8061fa07a..b5612cbb62a5 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -242,34 +242,38 @@ fail: } /** - * gfs2_unlinked_inode_lookup - Lookup an unlinked inode for reclamation + * gfs2_process_unlinked_inode - Lookup an unlinked inode for reclamation + * and try to reclaim it by doing iput. + * + * This function assumes no rgrp locks are currently held. + * * @sb: The super block * no_addr: The inode number - * @@inode: A pointer to the inode found, if any * - * Returns: 0 and *inode if no errors occurred. If an error occurs, - * the resulting *inode may or may not be NULL. */ -int gfs2_unlinked_inode_lookup(struct super_block *sb, u64 no_addr, - struct inode **inode) +void gfs2_process_unlinked_inode(struct super_block *sb, u64 no_addr) { struct gfs2_sbd *sdp; struct gfs2_inode *ip; struct gfs2_glock *io_gl; int error; struct gfs2_holder gh; + struct inode *inode; - *inode = gfs2_iget_skip(sb, no_addr); + inode = gfs2_iget_skip(sb, no_addr); - if (!(*inode)) - return -ENOBUFS; + if (!inode) + return; - if (!((*inode)->i_state & I_NEW)) - return -ENOBUFS; + /* If it's not a new inode, someone's using it, so leave it alone. */ + if (!(inode->i_state & I_NEW)) { + iput(inode); + return; + } - ip = GFS2_I(*inode); - sdp = GFS2_SB(*inode); + ip = GFS2_I(inode); + sdp = GFS2_SB(inode); ip->i_no_formal_ino = -1; error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl); @@ -284,15 +288,13 @@ int gfs2_unlinked_inode_lookup(struct super_block *sb, u64 no_addr, set_bit(GIF_INVALID, &ip->i_flags); error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, LM_FLAG_TRY | GL_EXACT, &ip->i_iopen_gh); - if (unlikely(error)) { - if (error == GLR_TRYFAILED) - error = 0; + if (unlikely(error)) goto fail_iopen; - } + ip->i_iopen_gh.gh_gl->gl_object = ip; gfs2_glock_put(io_gl); - (*inode)->i_mode = DT2IF(DT_UNKNOWN); + inode->i_mode = DT2IF(DT_UNKNOWN); /* * We must read the inode in order to work out its type in @@ -303,16 +305,17 @@ int gfs2_unlinked_inode_lookup(struct super_block *sb, u64 no_addr, */ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, LM_FLAG_TRY, &gh); - if (unlikely(error)) { - if (error == GLR_TRYFAILED) - error = 0; + if (unlikely(error)) goto fail_glock; - } + /* Inode is now uptodate */ gfs2_glock_dq_uninit(&gh); - gfs2_set_iop(*inode); + gfs2_set_iop(inode); + + /* The iput will cause it to be deleted. */ + iput(inode); + return; - return 0; fail_glock: gfs2_glock_dq(&ip->i_iopen_gh); fail_iopen: @@ -321,7 +324,8 @@ fail_put: ip->i_gl->gl_object = NULL; gfs2_glock_put(ip->i_gl); fail: - return error; + iget_failed(inode); + return; } static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf) diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index e161461d4c57..300ada3f21de 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -84,8 +84,7 @@ static inline void gfs2_inum_out(const struct gfs2_inode *ip, extern void gfs2_set_iop(struct inode *inode); extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, u64 no_addr, u64 no_formal_ino); -extern int gfs2_unlinked_inode_lookup(struct super_block *sb, u64 no_addr, - struct inode **inode); +extern void gfs2_process_unlinked_inode(struct super_block *sb, u64 no_addr); extern struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr); extern int gfs2_inode_refresh(struct gfs2_inode *ip); diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index b593f0e28f25..6a857e24f947 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -696,7 +696,7 @@ static void gfs2_ordered_wait(struct gfs2_sbd *sdp) * */ -void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) +void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) { struct gfs2_ail *ai; diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h index eb570b4ad443..0d007f920234 100644 --- a/fs/gfs2/log.h +++ b/fs/gfs2/log.h @@ -47,28 +47,21 @@ static inline void gfs2_log_pointers_init(struct gfs2_sbd *sdp, sdp->sd_log_head = sdp->sd_log_tail = value; } -unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, +extern unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, unsigned int ssize); -int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks); -void gfs2_log_incr_head(struct gfs2_sbd *sdp); +extern int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks); +extern void gfs2_log_incr_head(struct gfs2_sbd *sdp); -struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp); -struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, +extern struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp); +extern struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, struct buffer_head *real); -void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl); +extern void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl); +extern void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans); +extern void gfs2_remove_from_ail(struct gfs2_bufdata *bd); -static inline void gfs2_log_flush(struct gfs2_sbd *sbd, struct gfs2_glock *gl) -{ - if (!gl || test_bit(GLF_LFLUSH, &gl->gl_flags)) - __gfs2_log_flush(sbd, gl); -} - -void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans); -void gfs2_remove_from_ail(struct gfs2_bufdata *bd); - -void gfs2_log_shutdown(struct gfs2_sbd *sdp); -void gfs2_meta_syncfs(struct gfs2_sbd *sdp); -int gfs2_logd(void *data); +extern void gfs2_log_shutdown(struct gfs2_sbd *sdp); +extern void gfs2_meta_syncfs(struct gfs2_sbd *sdp); +extern int gfs2_logd(void *data); #endif /* __LOG_DOT_H__ */ diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 117fa4171f62..171a744f8e45 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1192,7 +1192,6 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al = ip->i_alloc; - struct inode *inode; int error = 0; u64 last_unlinked = NO_BLOCK, unlinked; @@ -1210,22 +1209,27 @@ try_again: if (error) return error; + /* Find an rgrp suitable for allocation. If it encounters any unlinked + dinodes along the way, error will equal -EAGAIN and unlinked will + contains it block address. We then need to look up that inode and + try to free it, and try the allocation again. */ error = get_local_rgrp(ip, &unlinked, &last_unlinked); if (error) { if (ip != GFS2_I(sdp->sd_rindex)) gfs2_glock_dq_uninit(&al->al_ri_gh); if (error != -EAGAIN) return error; - error = gfs2_unlinked_inode_lookup(ip->i_inode.i_sb, - unlinked, &inode); - if (inode) - iput(inode); + + gfs2_process_unlinked_inode(ip->i_inode.i_sb, unlinked); + /* regardless of whether or not gfs2_process_unlinked_inode + was successful, we don't want to repeat it again. */ + last_unlinked = unlinked; gfs2_log_flush(sdp, NULL); - if (error == GLR_TRYFAILED) - error = 0; + error = 0; + goto try_again; } - + /* no error, so we have the rgrp set in the inode's allocation. */ al->al_file = file; al->al_line = line; |