ocfs2: sysfs and cleanup
cover ocfs2: sysfs and cleanup
From: Goldwyn Rodrigues <[email protected]>
This adds /sys/fs/ocfs2/<s_id> to the sys filesystem. All other files are added in this directory. This is done by:
1. Adding kobject in the ocfs2_super structure
2. Using ocfs2_sb_attr which encompass all the show() and store() functions
This also reduce code and does away with unnecessary data structure, but adds some in the ocfs2_super for house keeping.
Hopefully, this would be used to further add configurable parameters for the super block.
Suggestions/Criticism welcome.
Signature · 1 line
Goldwyn
PATCH 1/5 ocfs2: Provisions for sysfs entries
From: Goldwyn Rodrigues <[email protected]>
This adds /sys/fs/ocfs2/<s_id> to the sys filesystem. This is done by adding the kobj into the ocfs2_super. All other files are added in this directory.
Introduce ocfs2_sb_attr which encompasses the store() and show() functions. Move all the important data structures with respect to filechecks to ocfs2_super.
More superblock information should move in here.
--- fs/ocfs2/Makefile | 3 +- fs/ocfs2/ocfs2.h | 4 +++ fs/ocfs2/super.c | 7 +++-- fs/ocfs2/sysfs.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/ocfs2/sysfs.h | 9 ++++++ 5 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 fs/ocfs2/sysfs.c create mode 100644 fs/ocfs2/sysfs.h
fs/ocfs2/Makefile +2 -1
@@ -41,7 +41,8 @@ ocfs2-objs := \ quota_local.o \ quota_global.o \ xattr.o \ - acl.o \ + acl.o \ + sysfs.o \ filecheck.o ocfs2_stackglue-objs := stackglue.o
fs/ocfs2/ocfs2.h +4 -0
@@ -37,6 +37,7 @@#include <linux/mutex.h> #include <linux/lockdep.h> #include <linux/jbd2.h> +#include <linux/kobject.h> /* For union ocfs2_dlm_lksb */ #include "stackglue.h"
@@ -472,6 +473,9 @@ struct ocfs2_super* workqueue and schedule on our own. */ struct workqueue_struct *ocfs2_wq; + +struct kobject kobj; +struct completion kobj_unregister; };#define OCFS2_SB (sb) ((struct ocfs2_super *)(sb)->s_fs_info)
fs/ocfs2/super.c +4 -3
@@ -75,6 +75,7 @@#include "buffer_head_io.h" #include "filecheck.h" +#include "sysfs.h" static struct kmem_cache *ocfs2_inode_cachep;struct kmem_cache *ocfs2_dquot_cachep;
@@ -1200,8 +1201,8 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)/* Start this when the mount is almost sure of being successful */ ocfs2_orphan_scan_start (osb); -/* Create filecheck sysfile /sys/fs/ocfs2/<devname>/filecheck */ -ocfs2_filecheck_create_sysfs (sb); +/* Create sysfs entries */ +ocfs2_sysfs_sb_init (sb);return status;
@@ -1651,9 +1652,9 @@ static void ocfs2_put_super(struct super_block *sb) {trace_ocfs2_put_super (sb); +ocfs2_sysfs_sb_exit (sb);ocfs2_sync_blockdev (sb);ocfs2_dismount_volume (sb,0 ); -ocfs2_filecheck_remove_sysfs (sb); }static int ocfs2_statfs (struct dentry *dentry,struct kstatfs *buf)
fs/ocfs2/sysfs.c new file +92 -0
92 lines not on this page · raw message
fs/ocfs2/sysfs.h new file +9 -0
@@ -0,0 +1,9 @@ + + +#ifndef _SYS_H +#define _SYS_H + +int ocfs2_sysfs_sb_init (struct super_block *sb); +void ocfs2_sysfs_sb_exit (struct super_block *sb); + +#endif
Signature · 1 line
2.6.6
PATCH 1/5 ocfs2: Provisions for sysfs entries
Quoted 125 lines · Goldwyn Rodrigues
From: Goldwyn Rodrigues <[email protected]>
This adds /sys/fs/ocfs2/<s_id> to the sys filesystem. This is done by adding the kobj into the
ocfs2_super. All other files are added in this directory.Introduce
ocfs2_sb_attrwhich encompasses thestore()andshow()functions. Move all the important data structures with respect to filechecks toocfs2_super.More superblock information should move in here.
Signed-off-by Goldwyn Rodrigues <[email protected]>--- fs/ocfs2/Makefile | 3 +- fs/ocfs2/ocfs2.h | 4 +++ fs/ocfs2/super.c | 7 +++-- fs/ocfs2/sysfs.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/ocfs2/sysfs.h | 9 ++++++ 5 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 fs/ocfs2/sysfs.c create mode 100644 fs/ocfs2/sysfs.hfs/ocfs2/Makefile +2
-1@@ -41,7 +41,8 @@ ocfs2-objs := \ quota_local.o \ quota_global.o \ xattr.o \ - acl.o \ + acl.o \ + sysfs.o \ filecheck.o ocfs2_stackglue-objs := stackglue.ofs/ocfs2/ocfs2.h +4
-0@@ -37,6 +37,7 @@#include <linux/mutex.h> #include <linux/lockdep.h> #include <linux/jbd2.h> +#include <linux/kobject.h> /* For union ocfs2_dlm_lksb */ #include "stackglue.h" @@ -472,6 +473,9 @@ struct ocfs2_super* workqueue and schedule on our own. */ struct workqueue_struct *ocfs2_wq; + +struct kobject kobj; +struct completion kobj_unregister; };#define OCFS2_SB (sb) ((struct ocfs2_super *)(sb)->s_fs_info)fs/ocfs2/super.c +4
-3@@ -75,6 +75,7 @@#include "buffer_head_io.h" #include "filecheck.h" +#include "sysfs.h" static struct kmem_cache *ocfs2_inode_cachep;struct kmem_cache *ocfs2_dquot_cachep;@@ -1200,8 +1201,8 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)/* Start this when the mount is almost sure of being successful */ ocfs2_orphan_scan_start (osb); -/* Create filecheck sysfile /sys/fs/ocfs2/<devname>/filecheck */ -ocfs2_filecheck_create_sysfs (sb); +/* Create sysfs entries */ +ocfs2_sysfs_sb_init (sb);return status;@@ -1651,9 +1652,9 @@ static void ocfs2_put_super(struct super_block *sb) {trace_ocfs2_put_super (sb); +ocfs2_sysfs_sb_exit (sb);ocfs2_sync_blockdev (sb);ocfs2_dismount_volume (sb,0 ); -ocfs2_filecheck_remove_sysfs (sb); }static int ocfs2_statfs (struct dentry *dentry,struct kstatfs *buf)fs/ocfs2/sysfs.c new file +26
-0@@ -0,0 +1,92 @@ +#include "ocfs2.h" +#include "sysfs.h" + +struct ocfs2_sb_attr { +struct attribute attr; +ssize_t (*show)(struct ocfs2_super *,struct ocfs2_sb_attr *, +char *buf); +ssize_t (*store)(struct ocfs2_super *,struct ocfs2_sb_attr *, +const char *buf,size_t count); +}; + +#define OCFS2_SB_ATTR (_name, _mode) \ +struct ocfs2_sb_attr sb_attr_##_name = __ATTR(name, _mode, _show, _store) + +#define OCFS2_SB_ATTR_RO (_name) \ +struct ocfs2_sb_attr sb_attr_##_name = __ATTR_RO(_name) + +static ssize_t ocfs2_sb_attr_show (struct kobject *kobj, +struct attribute *attr,char *buf) +{ +struct ocfs2_sb_attr *oa = + container_of(attr, struct ocfs2_sb_attr, attr); + struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj); +if (!oa->show) +return -EIO ; +
fs/ocfs2/sysfs.c line 36
Quoted 10 lines
fs/ocfs2/sysfs.c new file +10
-0+return oa->show (osb, oa, buf); +} + +static ssize_t ocfs2_sb_attr_store (struct kobject *kobj, +struct attribute *attr,const char *buf,size_t count) +{ +struct ocfs2_sb_attr *oa = + container_of(attr, struct ocfs2_sb_attr, attr); + struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj); +if (!oa->show)
Should it be "!oa->store" here?
Thanks,
Joseph
Quoted 72 lines
fs/ocfs2/sysfs.c new file +56
-0+return -EIO ; + +return oa->store (osb, oa, buf, count); +} + +static ssize_t slot_num_show (struct ocfs2_super *osb, +struct ocfs2_sb_attr *attr, +char *buf) +{ +return sprintf (buf,"%d\n" , osb->slot_num); +} + +static void sb_release (struct kobject *kobj) +{ + struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj); +complete (&osb->kobj_unregister); +} + +static const struct sysfs_ops ocfs2_sb_sysfs_ops = { + .show = ocfs2_sb_attr_show, + .store = ocfs2_sb_attr_store, +}; + +static OCFS2_SB_ATTR_RO (slot_num); +static struct attribute *ocfs2_sb_attrs[] = { + &sb_attr_slot_num.attr, +NULL +}; + +static struct kobj_type ocfs2_sb_ktype = { + .sysfs_ops = &ocfs2_sb_sysfs_ops, + .default_attrs = ocfs2_sb_attrs, + .release = sb_release, +}; + + +int ocfs2_sysfs_sb_init (struct super_block *sb) +{ +int err; +struct ocfs2_super *osb =OCFS2_SB (sb); +init_completion (&osb->kobj_unregister); + osb->kobj.kset = ocfs2_kset; + err =kobject_init_and_add (&osb->kobj, &ocfs2_sb_ktype,NULL ,"%s" , sb->s_id); +return err; + +} + +void ocfs2_sysfs_sb_exit (struct super_block *sb) +{ +struct ocfs2_super *osb =OCFS2_SB (sb); +kobject_del (&osb->kobj); +kobject_put (&osb->kobj); +wait_for_completion (&osb->kobj_unregister); +} + +fs/ocfs2/sysfs.h new file +9
-0@@ -0,0 +1,9 @@ + + +#ifndef _SYS_H +#define _SYS_H + +int ocfs2_sysfs_sb_init (struct super_block *sb); +void ocfs2_sysfs_sb_exit (struct super_block *sb); + +#endif
PATCH 1/5 ocfs2: Provisions for sysfs entries
Quoted 129 lines · Joseph Qi
Quoted 128 lines · Goldwyn Rodrigues
From: Goldwyn Rodrigues <[email protected]>
This adds /sys/fs/ocfs2/<s_id> to the sys filesystem. This is done by adding the kobj into the
ocfs2_super. All other files are added in this directory.Introduce
ocfs2_sb_attrwhich encompasses thestore()andshow()functions. Move all the important data structures with respect to filechecks toocfs2_super.More superblock information should move in here.
Signed-off-by Goldwyn Rodrigues <[email protected]>--- fs/ocfs2/Makefile | 3 +- fs/ocfs2/ocfs2.h | 4 +++ fs/ocfs2/super.c | 7 +++-- fs/ocfs2/sysfs.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/ocfs2/sysfs.h | 9 ++++++ 5 files changed, 111 insertions(+), 4 deletions(-)create mode 100644
fs/ocfs2/sysfs.c
create mode 100644fs/ocfs2/sysfs.hfs/ocfs2/Makefile +2
-1@@ -41,7 +41,8 @@ ocfs2-objs := \ quota_local.o \ quota_global.o \ xattr.o \ - acl.o \ + acl.o \ + sysfs.o \ filecheck.o ocfs2_stackglue-objs := stackglue.ofs/ocfs2/ocfs2.h +4
-0@@ -37,6 +37,7 @@#include <linux/mutex.h> #include <linux/lockdep.h> #include <linux/jbd2.h> +#include <linux/kobject.h> /* For union ocfs2_dlm_lksb */ #include "stackglue.h" @@ -472,6 +473,9 @@ struct ocfs2_super* workqueue and schedule on our own. */ struct workqueue_struct *ocfs2_wq; + +struct kobject kobj; +struct completion kobj_unregister; };#define OCFS2_SB (sb) ((struct ocfs2_super *)(sb)->s_fs_info)fs/ocfs2/super.c +4
-3@@ -75,6 +75,7 @@#include "buffer_head_io.h" #include "filecheck.h" +#include "sysfs.h" static struct kmem_cache *ocfs2_inode_cachep;struct kmem_cache *ocfs2_dquot_cachep;@@ -1200,8 +1201,8 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)/* Start this when the mount is almost sure of being successful */ ocfs2_orphan_scan_start (osb); -/* Create filecheck sysfile /sys/fs/ocfs2/<devname>/filecheck */ -ocfs2_filecheck_create_sysfs (sb); +/* Create sysfs entries */ +ocfs2_sysfs_sb_init (sb);return status;@@ -1651,9 +1652,9 @@ static void ocfs2_put_super(struct super_block *sb) {trace_ocfs2_put_super (sb); +ocfs2_sysfs_sb_exit (sb);ocfs2_sync_blockdev (sb);ocfs2_dismount_volume (sb,0 ); -ocfs2_filecheck_remove_sysfs (sb); }static int ocfs2_statfs (struct dentry *dentry,struct kstatfs *buf)fs/ocfs2/sysfs.c new file +29
-0@@ -0,0 +1,92 @@ +#include "ocfs2.h" +#include "sysfs.h" + +struct ocfs2_sb_attr { +struct attribute attr; +ssize_t (*show)(struct ocfs2_super *,struct ocfs2_sb_attr *, +char *buf); +ssize_t (*store)(struct ocfs2_super *,struct ocfs2_sb_attr *, +const char *buf,size_t count); +}; + +#define OCFS2_SB_ATTR (_name, _mode) \ +struct ocfs2_sb_attr sb_attr_##_name = __ATTR(name, _mode, _show, _store) + +#define OCFS2_SB_ATTR_RO (_name) \ +struct ocfs2_sb_attr sb_attr_##_name = __ATTR_RO(_name) + +static ssize_t ocfs2_sb_attr_show (struct kobject *kobj, +struct attribute *attr,char *buf) +{ +struct ocfs2_sb_attr *oa = + container_of(attr, struct ocfs2_sb_attr, attr); + struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj); +if (!oa->show) +return -EIO ; + +return oa->show (osb, oa, buf); +} +
Quoted 9 lines
fs/ocfs2/sysfs.c line 36
Quoted 7 lines
fs/ocfs2/sysfs.c new file +7
-0+static ssize_t ocfs2_sb_attr_store (struct kobject *kobj, +struct attribute *attr,const char *buf,size_t count) +{ +struct ocfs2_sb_attr *oa = + container_of(attr, struct ocfs2_sb_attr, attr); + struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj); +if (!oa->show)Should it be "!oa->store" here?
Yes, you are right. Thanks for pointing it out. I will fix this.
Signature · 1 line
Goldwyn
PATCH 2/5 Use the sysfs interface for creating filecheck files
In reply to Goldwyn RodriguesFrom: Goldwyn Rodrigues <[email protected]>
This reduces the code base and removes unnecessary data structures for filecheck information since all information is stored in ocfs2_super now.
--- fs/ocfs2/filecheck.c | 440 ++++++--------------------------------------------- fs/ocfs2/filecheck.h | 10 ++ fs/ocfs2/ocfs2.h | 7 + fs/ocfs2/super.c | 7 + fs/ocfs2/sysfs.c | 91 ++++++++++- 5 files changed, 161 insertions(+), 394 deletions(-)
fs/ocfs2/filecheck.c +48 -392
@@ -17,15 +17,7 @@* General Public License for more details. */ -#include <linux/list.h> -#include <linux/spinlock.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/kmod.h> #include <linux/fs.h> -#include <linux/kobject.h> -#include <linux/sysfs.h> -#include <linux/sysctl.h> #include <cluster/masklog.h> #include "ocfs2.h"
@@ -53,36 +45,6 @@ static const char * const ocfs2_filecheck_errs[] = {"UNSUPPORTED" }; -static DEFINE_SPINLOCK (ocfs2_filecheck_sysfs_lock); -static LIST_HEAD (ocfs2_filecheck_sysfs_list); - -struct ocfs2_filecheck { -struct list_head fc_head;/* File check entry list head */ -spinlock_t fc_lock; -unsigned int fc_max;/* Maximum number of entry in list */ -unsigned int fc_size;/* Current entry count in list */ -unsigned int fc_done;/* Finished entry count in list */ -}; - -struct ocfs2_filecheck_sysfs_entry {/* sysfs entry per mounting */ -struct list_head fs_list; -atomic_t fs_count; -struct super_block *fs_sb; -struct kset *fs_devicekset; -struct kset *fs_fcheckkset; -struct ocfs2_filecheck *fs_fcheck; -}; - -#define OCFS2_FILECHECK_MAXSIZE 100 -#define OCFS2_FILECHECK_MINSIZE 10 - -/* File check operation type */ -enum { -OCFS2_FILECHECK_TYPE_CHK =0 ,/* Check a file(inode) */ -OCFS2_FILECHECK_TYPE_FIX ,/* Fix a file(inode) */ -OCFS2_FILECHECK_TYPE_SET =100 /* Set entry list maximum size */ -}; -struct ocfs2_filecheck_entry {struct list_head fe_list;unsigned long fe_ino;
@@ -91,14 +53,6 @@ struct ocfs2_filecheck_entry { unsigned int fe_status:31; }; -struct ocfs2_filecheck_args { -unsigned int fa_type; -union { -unsigned long fa_ino; -unsigned int fa_len; - }; -}; -static const char *ocfs2_filecheck_error (int errno) {
@@ -110,321 +64,51 @@ ocfs2_filecheck_error(int errno)return ocfs2_filecheck_errs[errno -OCFS2_FILECHECK_ERR_START +1 ]; } -static ssize_t ocfs2_filecheck_show (struct kobject *kobj, -struct kobj_attribute *attr, -char *buf); -static ssize_t ocfs2_filecheck_store (struct kobject *kobj, -struct kobj_attribute *attr, -const char *buf,size_t count); -static struct kobj_attribute ocfs2_attr_filecheck_chk = -__ATTR (check,S_IRUSR |S_IWUSR , - ocfs2_filecheck_show, - ocfs2_filecheck_store); -static struct kobj_attribute ocfs2_attr_filecheck_fix = -__ATTR (fix,S_IRUSR |S_IWUSR , - ocfs2_filecheck_show, - ocfs2_filecheck_store); -static struct kobj_attribute ocfs2_attr_filecheck_set = -__ATTR (set,S_IRUSR |S_IWUSR , - ocfs2_filecheck_show, - ocfs2_filecheck_store); - -static int ocfs2_filecheck_sysfs_wait (atomic_t *p) -{ -schedule (); -return 0 ; -} - -static void -ocfs2_filecheck_sysfs_free (struct ocfs2_filecheck_sysfs_entry *entry) -{ -struct ocfs2_filecheck_entry *p; - -if (!atomic_dec_and_test (&entry->fs_count)) -wait_on_atomic_t (&entry->fs_count, ocfs2_filecheck_sysfs_wait, -TASK_UNINTERRUPTIBLE ); - -spin_lock (&entry->fs_fcheck->fc_lock); -while (!list_empty (&entry->fs_fcheck->fc_head)) { - p =list_first_entry (&entry->fs_fcheck->fc_head, - struct ocfs2_filecheck_entry, fe_list); -list_del (&p->fe_list); -BUG_ON (!p->fe_done);/* To free a undone file check entry */ -kfree (p); - } -spin_unlock (&entry->fs_fcheck->fc_lock); - -kset_unregister (entry->fs_fcheckkset); -kset_unregister (entry->fs_devicekset); -kfree (entry->fs_fcheck); -kfree (entry); -} - -static void -ocfs2_filecheck_sysfs_add (struct ocfs2_filecheck_sysfs_entry *entry) -{ -spin_lock (&ocfs2_filecheck_sysfs_lock); -list_add_tail (&entry->fs_list, &ocfs2_filecheck_sysfs_list); -spin_unlock (&ocfs2_filecheck_sysfs_lock); -} - -static int ocfs2_filecheck_sysfs_del (const char *devname) -{ -struct ocfs2_filecheck_sysfs_entry *p; - -spin_lock (&ocfs2_filecheck_sysfs_lock); -list_for_each_entry (p, &ocfs2_filecheck_sysfs_list, fs_list) { -if (!strcmp (p->fs_sb->s_id, devname)) { -list_del (&p->fs_list); -spin_unlock (&ocfs2_filecheck_sysfs_lock); -ocfs2_filecheck_sysfs_free (p); -return 0 ; - } - } -spin_unlock (&ocfs2_filecheck_sysfs_lock); -return 1 ; -} - -static void -ocfs2_filecheck_sysfs_put (struct ocfs2_filecheck_sysfs_entry *entry) -{ -if (atomic_dec_and_test (&entry->fs_count)) -wake_up_atomic_t (&entry->fs_count); -} - -static struct ocfs2_filecheck_sysfs_entry * -ocfs2_filecheck_sysfs_get (const char *devname) -{ -struct ocfs2_filecheck_sysfs_entry *p =NULL ; - -spin_lock (&ocfs2_filecheck_sysfs_lock); -list_for_each_entry (p, &ocfs2_filecheck_sysfs_list, fs_list) { -if (!strcmp (p->fs_sb->s_id, devname)) { -atomic_inc (&p->fs_count); -spin_unlock (&ocfs2_filecheck_sysfs_lock); -return p; - } - } -spin_unlock (&ocfs2_filecheck_sysfs_lock); -return NULL ; -} - -int ocfs2_filecheck_create_sysfs (struct super_block *sb) -{ -int ret =0 ; -struct kset *device_kset =NULL ; -struct kset *fcheck_kset =NULL ; -struct ocfs2_filecheck *fcheck =NULL ; -struct ocfs2_filecheck_sysfs_entry *entry =NULL ; -struct attribute **attrs =NULL ; -struct attribute_group attrgp; - -if (!ocfs2_kset) -return -ENOMEM ; - - attrs =kmalloc (sizeof (struct attribute *) *4 ,GFP_NOFS ); -if (!attrs) { - ret = -ENOMEM ; - goto error; - }else { - attrs[0 ] = &ocfs2_attr_filecheck_chk.attr; - attrs[1 ] = &ocfs2_attr_filecheck_fix.attr; - attrs[2 ] = &ocfs2_attr_filecheck_set.attr; - attrs[3 ] =NULL ; -memset (&attrgp,0 ,sizeof (attrgp)); - attrgp.attrs = attrs; - } - - fcheck =kmalloc (sizeof (struct ocfs2_filecheck ),GFP_NOFS ); -if (!fcheck) { - ret = -ENOMEM ; - goto error; - }else { -INIT_LIST_HEAD (&fcheck->fc_head); -spin_lock_init (&fcheck->fc_lock); - fcheck->fc_max =OCFS2_FILECHECK_MINSIZE ; - fcheck->fc_size =0 ; - fcheck->fc_done =0 ; - } - -if (strlen (sb->s_id) <=0 ) { -mlog (ML_ERROR , -"Cannot get device basename when create filecheck sysfs\n" ); - ret = -ENODEV ; - goto error; - } - - device_kset =kset_create_and_add (sb->s_id,NULL , &ocfs2_kset->kobj); -if (!device_kset) { - ret = -ENOMEM ; - goto error; - } - - fcheck_kset =kset_create_and_add ("filecheck" ,NULL , - &device_kset->kobj); -if (!fcheck_kset) { - ret = -ENOMEM ; - goto error; - } - - ret =sysfs_create_group (&fcheck_kset->kobj, &attrgp); -if (ret) - goto error; - - entry =kmalloc (sizeof (struct ocfs2_filecheck_sysfs_entry ),GFP_NOFS ); -if (!entry) { - ret = -ENOMEM ; - goto error; - }else { -atomic_set (&entry->fs_count,1 ); - entry->fs_sb = sb; - entry->fs_devicekset = device_kset; - entry->fs_fcheckkset = fcheck_kset; - entry->fs_fcheck = fcheck; -ocfs2_filecheck_sysfs_add (entry); - } - -kfree (attrs); -return 0 ; - -error: -kfree (attrs); -kfree (entry); -kfree (fcheck); -kset_unregister (fcheck_kset); -kset_unregister (device_kset); -return ret; -} - -int ocfs2_filecheck_remove_sysfs (struct super_block *sb) -{ -return ocfs2_filecheck_sysfs_del (sb->s_id); -} -static int -ocfs2_filecheck_erase_entries (struct ocfs2_filecheck_sysfs_entry *ent, +ocfs2_filecheck_erase_entries (struct ocfs2_super *,unsigned int count); -static int -ocfs2_filecheck_adjust_max (struct ocfs2_filecheck_sysfs_entry *ent, -unsigned int len) + +int ocfs2_filecheck_set_max_entries (struct ocfs2_super *osb, +int len) {int ret;if ((len <OCFS2_FILECHECK_MINSIZE ) || (len >OCFS2_FILECHECK_MAXSIZE ))return -EINVAL ; -spin_lock (&ent->fs_fcheck->fc_lock); -if (len < (ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done)) { +spin_lock (&osb->fc_lock); +if (len < (osb->fc_size - osb->fc_done)) {mlog (ML_ERROR ,"Cannot set online file check maximum entry number " "to %u due to too many pending entries(%u)\n" , - len, ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done); + len, osb->fc_size - osb->fc_done); ret = -EBUSY ; }else { -if (len < ent->fs_fcheck->fc_size) -BUG_ON (!ocfs2_filecheck_erase_entries (ent, - ent->fs_fcheck->fc_size - len)); +if (len < osb->fc_size) +BUG_ON (!ocfs2_filecheck_erase_entries (osb, + osb->fc_size - len)); - ent->fs_fcheck->fc_max = len; + osb->fc_max = len; ret =0 ; } -spin_unlock (&ent->fs_fcheck->fc_lock); +spin_unlock (&osb->fc_lock);return ret; } -#define OCFS2_FILECHECK_ARGS_LEN 24 -static int -ocfs2_filecheck_args_get_long (const char *buf,size_t count, -unsigned long *val) -{ -char buffer[OCFS2_FILECHECK_ARGS_LEN ]; - -memcpy (buffer, buf, count); - buffer[count] ='\0' ; - -if (kstrtoul (buffer,0 , val)) -return 1 ; - -return 0 ; -} - -static int -ocfs2_filecheck_type_parse (const char *name,unsigned int *type) -{ -if (!strncmp (name,"fix" ,4 )) - *type =OCFS2_FILECHECK_TYPE_FIX ; -else if (!strncmp (name,"check" ,6 )) - *type =OCFS2_FILECHECK_TYPE_CHK ; -else if (!strncmp (name,"set" ,4 )) - *type =OCFS2_FILECHECK_TYPE_SET ; -else -return 1 ; - -return 0 ; -} - -static int -ocfs2_filecheck_args_parse (const char *name,const char *buf,size_t count, -struct ocfs2_filecheck_args *args) -{ -unsigned long val =0 ; -unsigned int type; - -/* too short/long args length */ -if ((count <1 ) || (count >=OCFS2_FILECHECK_ARGS_LEN )) -return 1 ; - -if (ocfs2_filecheck_type_parse (name, &type)) -return 1 ; -if (ocfs2_filecheck_args_get_long (buf, count, &val)) -return 1 ; - -if (val <=0 ) -return 1 ; - args->fa_type = type; -if (type ==OCFS2_FILECHECK_TYPE_SET ) - args->fa_len = (unsigned int )val; -else - args->fa_ino = val; - -return 0 ; -} - -static ssize_t ocfs2_filecheck_show (struct kobject *kobj, -struct kobj_attribute *attr, +int ocfs2_filecheck_show (struct ocfs2_super *osb,unsigned int type,char *buf) {ssize_t ret =0 , total =0 , remain =PAGE_SIZE ; -unsigned int type;struct ocfs2_filecheck_entry *p; -struct ocfs2_filecheck_sysfs_entry *ent; - -if (ocfs2_filecheck_type_parse (attr->attr.name, &type)) -return -EINVAL ; - - ent =ocfs2_filecheck_sysfs_get (kobj->parent->name); -if (!ent) { -mlog (ML_ERROR , -"Cannot get the corresponding entry via device basename %s\n" , - kobj->name); -return -ENODEV ; - } - -if (type ==OCFS2_FILECHECK_TYPE_SET ) { -spin_lock (&ent->fs_fcheck->fc_lock); - total =snprintf (buf, remain,"%u\n" , ent->fs_fcheck->fc_max); -spin_unlock (&ent->fs_fcheck->fc_lock); - goto exit; - } ret =snprintf (buf, remain,"INO\t\tDONE\tERROR\n" ); total += ret; remain -= ret; -spin_lock (&ent->fs_fcheck->fc_lock); -list_for_each_entry (p, &ent->fs_fcheck->fc_head, fe_list) { +spin_lock (&osb->fc_lock); +list_for_each_entry (p, &osb->file_check_entries, fe_list) {if (p->fe_type != type)continue ;
@@ -443,24 +127,21 @@ static ssize_t ocfs2_filecheck_show(struct kobject *kobj, total += ret; remain -= ret; } -spin_unlock (&ent->fs_fcheck->fc_lock); - -exit: -ocfs2_filecheck_sysfs_put (ent); +spin_unlock (&osb->fc_lock);return total; }static int -ocfs2_filecheck_erase_entry (struct ocfs2_filecheck_sysfs_entry *ent) +ocfs2_filecheck_erase_entry (struct ocfs2_super *osb) {struct ocfs2_filecheck_entry *p; -list_for_each_entry (p, &ent->fs_fcheck->fc_head, fe_list) { +list_for_each_entry (p, &osb->file_check_entries, fe_list) {if (p->fe_done) {list_del (&p->fe_list);kfree (p); - ent->fs_fcheck->fc_size--; - ent->fs_fcheck->fc_done--; + osb->fc_size--; + osb->fc_done--;return 1 ; } }
@@ -469,14 +150,14 @@ ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent) }static int -ocfs2_filecheck_erase_entries (struct ocfs2_filecheck_sysfs_entry *ent, +ocfs2_filecheck_erase_entries (struct ocfs2_super *osb,unsigned int count) {unsigned int i =0 ;unsigned int ret =0 ;while (i++ < count) { -if (ocfs2_filecheck_erase_entry (ent)) +if (ocfs2_filecheck_erase_entry (osb)) ret++;else break ;
@@ -486,24 +167,24 @@ ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent, }static void -ocfs2_filecheck_done_entry (struct ocfs2_filecheck_sysfs_entry *ent, +ocfs2_filecheck_done_entry (struct ocfs2_super *osb,struct ocfs2_filecheck_entry *entry) { entry->fe_done =1 ; -spin_lock (&ent->fs_fcheck->fc_lock); - ent->fs_fcheck->fc_done++; -spin_unlock (&ent->fs_fcheck->fc_lock); +spin_lock (&osb->fc_lock); + osb->fc_done++; +spin_unlock (&osb->fc_lock); }static unsigned int -ocfs2_filecheck_handle (struct super_block *sb, +ocfs2_filecheck_handle (struct ocfs2_super *osb,unsigned long ino,unsigned int flags) {unsigned int ret =OCFS2_FILECHECK_ERR_SUCCESS ;struct inode *inode =NULL ;int rc; - inode =ocfs2_iget (OCFS2_SB (sb), ino, flags,0 ); + inode =ocfs2_iget (osb, ino, flags,0 );if (IS_ERR (inode)) { rc = (int )(-(long )inode); if (rc >= OCFS2_FILECHECK_ERR_START &&
@@ -518,89 +199,64 @@ ocfs2_filecheck_handle(struct super_block *sb, }static void -ocfs2_filecheck_handle_entry (struct ocfs2_filecheck_sysfs_entry *ent, +ocfs2_filecheck_handle_entry (struct ocfs2_super *osb,struct ocfs2_filecheck_entry *entry) {if (entry->fe_type ==OCFS2_FILECHECK_TYPE_CHK ) - entry->fe_status =ocfs2_filecheck_handle (ent->fs_sb, + entry->fe_status =ocfs2_filecheck_handle (osb, entry->fe_ino,OCFS2_FI_FLAG_FILECHECK_CHK );else if (entry->fe_type ==OCFS2_FILECHECK_TYPE_FIX ) - entry->fe_status =ocfs2_filecheck_handle (ent->fs_sb, + entry->fe_status =ocfs2_filecheck_handle (osb, entry->fe_ino,OCFS2_FI_FLAG_FILECHECK_FIX );else entry->fe_status =OCFS2_FILECHECK_ERR_UNSUPPORTED ; -ocfs2_filecheck_done_entry (ent, entry); +ocfs2_filecheck_done_entry (osb, entry); } -static ssize_t ocfs2_filecheck_store (struct kobject *kobj, -struct kobj_attribute *attr, -const char *buf,size_t count) +int ocfs2_filecheck_add_inode (struct ocfs2_super *osb, +unsigned long ino) { -struct ocfs2_filecheck_args args;struct ocfs2_filecheck_entry *entry; -struct ocfs2_filecheck_sysfs_entry *ent;ssize_t ret =0 ; -if (count ==0 ) -return count; - -if (ocfs2_filecheck_args_parse (attr->attr.name, buf, count, &args)) { -mlog (ML_ERROR ,"Invalid arguments for online file check\n" ); -return -EINVAL ; - } - - ent =ocfs2_filecheck_sysfs_get (kobj->parent->name); -if (!ent) { -mlog (ML_ERROR , -"Cannot get the corresponding entry via device basename %s\n" , - kobj->parent->name); -return -ENODEV ; - } - -if (args.fa_type ==OCFS2_FILECHECK_TYPE_SET ) { - ret =ocfs2_filecheck_adjust_max (ent, args.fa_len); - goto exit; - } - entry =kmalloc (sizeof (struct ocfs2_filecheck_entry ),GFP_NOFS );if (!entry) { ret = -ENOMEM ; goto exit; } -spin_lock (&ent->fs_fcheck->fc_lock); -if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) && - (ent->fs_fcheck->fc_done ==0 )) { +spin_lock (&osb->fc_lock); +if ((osb->fc_size >= osb->fc_max) && + (osb->fc_done ==0 )) {mlog (ML_ERROR ,"Cannot do more file check " "since file check queue(%u) is full now\n" , - ent->fs_fcheck->fc_max); + osb->fc_max); ret = -EBUSY ;kfree (entry); }else { -if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) && - (ent->fs_fcheck->fc_done >0 )) { +if ((osb->fc_size >= osb->fc_max) && + (osb->fc_done >0 )) {/* Delete the oldest entry which was done, * make sure the entry size in list does * not exceed maximum value */ -BUG_ON (!ocfs2_filecheck_erase_entry (ent)); +BUG_ON (!ocfs2_filecheck_erase_entry (osb)); } - entry->fe_ino = args.fa_ino; - entry->fe_type = args.fa_type; + entry->fe_ino = ino; + entry->fe_type =OCFS2_FILECHECK_TYPE_CHK ; entry->fe_done =0 ; entry->fe_status =OCFS2_FILECHECK_ERR_INPROGRESS ; -list_add_tail (&entry->fe_list, &ent->fs_fcheck->fc_head); - ent->fs_fcheck->fc_size++; +list_add_tail (&entry->fe_list, &osb->file_check_entries); + osb->fc_size++; } -spin_unlock (&ent->fs_fcheck->fc_lock); +spin_unlock (&osb->fc_lock);if (!ret) -ocfs2_filecheck_handle_entry (ent, entry); +ocfs2_filecheck_handle_entry (osb, entry); exit: -ocfs2_filecheck_sysfs_put (ent); -return (!ret ? count : ret); +return ret; }
fs/ocfs2/filecheck.h +10 -0
@@ -42,8 +42,18 @@ enum {#define OCFS2_FILECHECK_ERR_START OCFS2_FILECHECK_ERR_FAILED#define OCFS2_FILECHECK_ERR_END OCFS2_FILECHECK_ERR_UNSUPPORTED +#define OCFS2_FILECHECK_MAXSIZE 100 +#define OCFS2_FILECHECK_MINSIZE 10 + +/* File check operation type */ +#define OCFS2_FILECHECK_TYPE_CHK 1/* Check a file(inode) */ +#define OCFS2_FILECHECK_TYPE_FIX 2/* Fix a file(inode) */ int ocfs2_filecheck_create_sysfs (struct super_block *sb);int ocfs2_filecheck_remove_sysfs (struct super_block *sb); +int ocfs2_filefix_inode (struct ocfs2_super *osb,unsigned long ino); +int ocfs2_filecheck_add_inode (struct ocfs2_super *osb,unsigned long ino); +int ocfs2_filecheck_set_max_entries (struct ocfs2_super *osb,int num); +int ocfs2_filecheck_show (struct ocfs2_super *osb,unsigned int type,char *buf);#endif /* FILECHECK_H */
fs/ocfs2/ocfs2.h +7 -0
@@ -474,6 +474,13 @@ struct ocfs2_super*/ struct workqueue_struct *ocfs2_wq; +/* file check */ +struct list_head file_check_entries; +unsigned int fc_size; +unsigned int fc_max; +unsigned int fc_done; +spinlock_t fc_lock; +struct kobject kobj;struct completion kobj_unregister; };
fs/ocfs2/super.c +7 -0
@@ -2215,6 +2215,13 @@ static int ocfs2_initialize_super(struct super_block *sb,get_random_bytes (&osb->s_next_generation,sizeof (u32)); +/* file check information */ +INIT_LIST_HEAD (&osb->file_check_entries); + osb->fc_max =OCFS2_FILECHECK_MINSIZE ; + osb->fc_size =0 ; + osb->fc_done =0 ; +spin_lock_init (&osb->fc_lock); +/* FIXME * This should be done in ocfs2_journal_init(), but unknown * ordering issues will cause the filesystem to crash.
fs/ocfs2/sysfs.c +89 -2
116 lines not on this page · raw message
Signature · 1 line
2.6.6
PATCH 3/5 Generate uevents for errors
In reply to Goldwyn RodriguesFrom: Goldwyn Rodrigues <[email protected]>
Errors are reported to the userspace using the kobject we just added. This can be used to automate checks and fixes using udev scripts
--- fs/ocfs2/inode.c | 13 +++++++++++++ fs/ocfs2/sysfs.c | 17 +++++++++++++++++ fs/ocfs2/sysfs.h | 2 ++ 3 files changed, 32 insertions(+)
fs/ocfs2/inode.c +13 -0
@@ -54,6 +54,7 @@#include "refcounttree.h" #include "ocfs2_trace.h" #include "filecheck.h" +#include "sysfs.h" #include "buffer_head_io.h"
@@ -1412,6 +1413,9 @@ int ocfs2_validate_inode_block(struct super_block *sb, rc =ocfs2_error (sb,"Invalid dinode #%llu: signature = %.*s\n" , (unsigned long long )bh->b_blocknr,7 , di->i_signature); +ocfs2_report_error (OCFS2_SB (sb), (unsigned long long )bh->b_blocknr, + (unsigned long long )bh->b_blocknr, + rc); goto bail; }
@@ -1419,6 +1423,9 @@ int ocfs2_validate_inode_block(struct super_block *sb, rc =ocfs2_error (sb,"Invalid dinode #%llu: i_blkno is %llu\n" , (unsigned long long )bh->b_blocknr, (unsigned long long )le64_to_cpu (di->i_blkno)); +ocfs2_report_error (OCFS2_SB (sb), (unsigned long long )bh->b_blocknr, + (unsigned long long )bh->b_blocknr, + rc); goto bail; }
@@ -1426,6 +1433,9 @@ int ocfs2_validate_inode_block(struct super_block *sb, rc =ocfs2_error (sb,"Invalid dinode #%llu: OCFS2_VALID_FL not set\n" , (unsigned long long )bh->b_blocknr); +ocfs2_report_error (OCFS2_SB (sb), (unsigned long long )bh->b_blocknr, + (unsigned long long )bh->b_blocknr, + rc); goto bail; }
@@ -1435,6 +1445,9 @@ int ocfs2_validate_inode_block(struct super_block *sb,"Invalid dinode #%llu: fs_generation is %u\n" , (unsigned long long )bh->b_blocknr, le32_to_cpu(di->i_fs_generation)); +ocfs2_report_error (OCFS2_SB (sb), (unsigned long long )bh->b_blocknr, + (unsigned long long )bh->b_blocknr, + rc); goto bail; }
fs/ocfs2/sysfs.c +17 -0
@@ -126,6 +126,23 @@ static ssize_t file_check_max_entries_store(struct ocfs2_super *osb,return count; } +void ocfs2_report_error (struct ocfs2_super *osb,unsigned long long ino, +unsigned long long blkno,int errno) +{ +char event_name[] ="EVENT=FS_ERROR" ; +char device[16 ]; +char inode_number[16 ]; +char error_number[16 ]; +char block_number[16 ]; +char *envp[] = {event_name, inode_number, error_number, block_number, +NULL }; +snprintf (device,16 ,"DEVICE=%s" , osb->sb->s_id); +snprintf (error_number,16 ,"ERROR=%d" , errno); +snprintf (inode_number,16 ,"INODE=%llu" , ino); +snprintf (block_number,16 ,"BLOCK=%llu" , blkno); +kobject_uevent_env (&osb->kobj,KOBJ_CHANGE , envp); +} +static void sb_release (struct kobject *kobj) { struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj);
fs/ocfs2/sysfs.h +2 -0
@@ -3,6 +3,8 @@#ifndef _SYS_H#define _SYS_H +void ocfs2_report_error (struct ocfs2_super *osb,unsigned long long ino, +unsigned long long blkno,int error);int ocfs2_sysfs_sb_init (struct super_block *sb);void ocfs2_sysfs_sb_exit (struct super_block *sb);
Signature · 1 line
2.6.6
PATCH 4/5 ocfs2: Disallow duplicate entries in the list
In reply to Goldwyn RodriguesFrom: Goldwyn Rodrigues <[email protected]>
A check to make sure we don't have duplicates in the filecheck list.
--- fs/ocfs2/filecheck.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-)
fs/ocfs2/filecheck.c +17 -9
@@ -217,14 +217,12 @@ ocfs2_filecheck_handle_entry(struct ocfs2_super *osb,int ocfs2_filecheck_add_inode (struct ocfs2_super *osb,unsigned long ino) { -struct ocfs2_filecheck_entry *entry; +struct ocfs2_filecheck_entry *entry, *p;ssize_t ret =0 ; entry =kmalloc (sizeof (struct ocfs2_filecheck_entry ),GFP_NOFS ); -if (!entry) { - ret = -ENOMEM ; - goto exit; - } +if (!entry) +return -ENOMEM ;spin_lock (&osb->fc_lock); if ((osb->fc_size >= osb->fc_max) &&
@@ -244,6 +242,12 @@ int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,*/ BUG_ON (!ocfs2_filecheck_erase_entry (osb)); } +list_for_each_entry (p, &osb->file_check_entries, fe_list) +if (p->fe_ino == ino) { + ret = -EEXIST ; +kfree (entry); + goto unlock; + } entry->fe_ino = ino; entry->fe_type =OCFS2_FILECHECK_TYPE_CHK ;
@@ -252,11 +256,15 @@ int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,list_add_tail (&entry->fe_list, &osb->file_check_entries); osb->fc_size++; } +unlock:spin_unlock (&osb->fc_lock); -if (!ret) -ocfs2_filecheck_handle_entry (osb, entry); +if (ret) +return ret; -exit: -return ret; + entry->fe_status =ocfs2_filecheck_handle (osb, + entry->fe_ino,OCFS2_FI_FLAG_FILECHECK_CHK ); + +ocfs2_filecheck_done_entry (osb, entry); +return 0 ; }
Signature · 1 line
2.6.6
PATCH 5/5 Fix files when an inode is written in file_fix
In reply to Goldwyn RodriguesFrom: Goldwyn Rodrigues <[email protected]>
Check that the entriy exists and has been filed for check. Also perform some code cleanup to remove ocfs2_filecheck_handle_entry()
--- fs/ocfs2/filecheck.c | 41 +++++++++++++++++++++++++---------------- fs/ocfs2/filecheck.h | 1 + fs/ocfs2/sysfs.c | 2 +- 3 files changed, 27 insertions(+), 17 deletions(-)
fs/ocfs2/filecheck.c +25 -16
@@ -198,22 +198,6 @@ ocfs2_filecheck_handle(struct ocfs2_super *osb,return ret; } -static void -ocfs2_filecheck_handle_entry (struct ocfs2_super *osb, -struct ocfs2_filecheck_entry *entry) -{ -if (entry->fe_type ==OCFS2_FILECHECK_TYPE_CHK ) - entry->fe_status =ocfs2_filecheck_handle (osb, - entry->fe_ino,OCFS2_FI_FLAG_FILECHECK_CHK ); -else if (entry->fe_type ==OCFS2_FILECHECK_TYPE_FIX ) - entry->fe_status =ocfs2_filecheck_handle (osb, - entry->fe_ino,OCFS2_FI_FLAG_FILECHECK_FIX ); -else - entry->fe_status =OCFS2_FILECHECK_ERR_UNSUPPORTED ; - -ocfs2_filecheck_done_entry (osb, entry); -} -int ocfs2_filecheck_add_inode (struct ocfs2_super *osb,unsigned long ino) {
@@ -268,3 +252,28 @@ unlock:ocfs2_filecheck_done_entry (osb, entry);return 0 ; } + +int ocfs2_filefix_add_inode (struct ocfs2_super *osb, +unsigned long ino) +{ +struct ocfs2_filecheck_entry *entry; +int ret = -ENOENT ; + +spin_lock (&osb->fc_lock); +list_for_each_entry (entry, &osb->file_check_entries, fe_list) +if (entry->fe_ino == ino) { + entry->fe_type =OCFS2_FILECHECK_TYPE_FIX ; + ret =0 ; +break ; + } +spin_unlock (&osb->fc_lock); +if (ret) +return ret; + + entry->fe_status =ocfs2_filecheck_handle (osb, + entry->fe_ino,OCFS2_FI_FLAG_FILECHECK_FIX ); + +ocfs2_filecheck_done_entry (osb, entry); +return 0 ; +} +
fs/ocfs2/filecheck.h +1 -0
@@ -53,6 +53,7 @@ int ocfs2_filecheck_create_sysfs(struct super_block *sb);int ocfs2_filecheck_remove_sysfs (struct super_block *sb);int ocfs2_filefix_inode (struct ocfs2_super *osb,unsigned long ino);int ocfs2_filecheck_add_inode (struct ocfs2_super *osb,unsigned long ino); +int ocfs2_filefix_add_inode (struct ocfs2_super *osb,unsigned long ino);int ocfs2_filecheck_set_max_entries (struct ocfs2_super *osb,int num);int ocfs2_filecheck_show (struct ocfs2_super *osb,unsigned int type,char *buf);
fs/ocfs2/sysfs.c +1 -1
@@ -91,7 +91,7 @@ static ssize_t file_fix_store(struct ocfs2_super *osb, ret =kstrtoul (skip_spaces (buf),0 , &t);if (ret)return ret; - ret =ocfs2_filecheck_add_inode (osb, t); + ret =ocfs2_filefix_add_inode (osb, t);if (ret)return ret;return count;
Signature · 1 line
2.6.6
cover ocfs2: sysfs and cleanup
In reply to Goldwyn RodriguesHello Goldwyn,
Thank for your efforts on improving online file check. I was being engaged by some bugs in the past days.
Thanks
Gang
Quoted 18 lines
Quoted 1 line
Quoted 1 line
From: Goldwyn Rodrigues <[email protected]>
This adds /sys/fs/ocfs2/<s_id> to the sys filesystem. All other files are added in this directory. This is done by:
1. Adding kobject in theocfs2_superstructure
2. Usingocfs2_sb_attrwhich encompass all theshow()andstore()functionsThis also reduce code and does away with unnecessary data structure, but adds some in the
ocfs2_superfor house keeping.Hopefully, this would be used to further add configurable parameters for the super block.
Suggestions/Criticism welcome.
Signature · 1 line
Goldwyn